--- /dev/null
+---
+BasedOnStyle: Google
+
+# Good:
+#
+# class Foo
+# {
+# public:
+#
+# Foo() = default;
+#
+# };
+#
+# Bad:
+#
+# class Foo
+# {
+# public:
+#
+# Foo() = default;
+#
+# };
+#
+AccessModifierOffset: -4
+
+# Good:
+#
+# clang = Clang(); // Comment 1
+# format = Format(); // Comment 2
+#
+# Bad:
+# clang = Clang(); // Comment 1
+# format = Format(); // Comment 2
+#
+AlignTrailingComments: false
+AllowShortFunctionsOnASingleLine: false
+AllowShortBlocksOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+
+# Good:
+#
+# void F(int first,
+# int second,
+# int third,
+# int fourth,
+# int fifth,
+# int sixth,
+# int seventh,
+# int eighth) {}
+#
+# Bad:
+#
+# void F(int first, int second, int third, int fourth, int fifth, int sixth,
+# int seventh, int eighth) {}
+#
+BinPackParameters: false
+BinPackArguments: false
+
+# Like 'Attach', but break before braces on function, namespaces, class, struct
+# and union definitions.
+#
+BreakBeforeBraces: Linux
+
+# Good:
+#
+# class Foo
+# {
+# public:
+#
+# Foo()
+# : first(1), second(2) {}
+#
+# };
+#
+# Bad:
+#
+# class Foo
+# {
+# public:
+#
+# Foo()
+# : first(1), second(2) {}
+#
+# };
+#
+ConstructorInitializerIndentWidth: 4
+IndentWidth: 4
+
+# Continuation indents such as assignment statements are indented by 2 spaces.
+ContinuationIndentWidth: 4
+
+PointerAlignment: Right
+# Don't try to guess the pointer alignment
+DerivePointerAlignment: false
+
+# List of foreach macros due to lack of range-based for loops.
+ForEachMacros: [ foreach, foreachkey, foreachvalue, foreachpair ]
+
+# Maximum number of empty lines to keep.
+MaxEmptyLinesToKeep: 2
+
+# Good:
+#
+# x = 42; // Comment
+#
+# Bad:
+#
+# x = 42; // Comment
+#
+SpacesBeforeTrailingComments: 1
+...
--- /dev/null
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.dll.a
+
+# executables
+seafile-applet
+orig-seafile-applet
+*.exe
+
+# backup file
+*#
+*~
+*.bak
+
+# other formats
+cscope*
+core
+*.pyc
+.DS_Store
+
+# CMake files goes here
+build/
+CMakeCache.txt
+CMakeFiles/
+Makefile
+cmake_install.cmake
+CTestTestfile.cmake
+Testing/
+install_manifest.txt
+
+#### Qt files goes here
+### moc
+moc_*.cxx*
+moc_*.cpp*
+*.moc
+
+### ui
+ui_*.h
+
+### qrc
+*.qrc.depends
+qrc_*.cxx
+qrc_*.cpp
+
+i18n/*.qm
+
+### emacs files
+.emacs*
+.#*
+
+### ninja files
+.ninja_deps
+.ninja_log
+build.ninja
+rules.ninja
+
+## xcode related
+Debug
+Release
+seafile-client.xcodeproj
+CMakeScripts
+seafile-applet.app
+seafile-fsplugin.xcodeproj
+Seafile FinderSync.appex
+
+## unittest related
+test_*
+!test_*.cpp
+!test_*.h
+
+## doxygen related
+docs
+Doxyfile
+
+## breakpad related
+third_party/gyp
+third_party/breakpad
+
+/GPATH
+/GTAGS
+/GRTAGS
+/gtags.files
+
+.deps
+compile_commands.json
+.ycm_extra_conf.py
+seafile-applet.rc
+*.dmp
+
+*seafile-applet
+*.lib
+
+## vscode
+.vscode/
--- /dev/null
+sudo: required
+dist: trusty
+language: cpp
+matrix:
+ include:
+ - os: linux
+ compiler: gcc
+ env: BUILD_SHIBBOLETH_SUPPORT=ON
+ - os: linux
+ compiler: gcc
+ env: BUILD_SHIBBOLETH_SUPPORT=OFF
+ exclude:
+ - os: osx
+ compiler: gcc
+before_install:
+ - ./scripts/install-deps-${TRAVIS_OS_NAME}.sh
+script:
+ - ./scripts/ci-build.sh
+notifications:
+ email:
+ recipients:
+ - linshuai2012@gmail.com
+ - rwindz0@gmail.com
+ slack:
+ secure: RhwjY2BL0bR6MD+ASvFptH9GJmT0CshRN4YoZgK80D/H1kK60nVjfYIwU0apmhG8J3Sz9jqQ5xGPBUXvAgKB9VzdGQVgo23kGm9P2AY6xM43HHcPJvuXEBeX6zCx1O2HyGmENq36Z9ZnDWxW9yswnXKmeb05lE+PisBn1XvWQrs=
+ on_success: change
+ on_failure: always
--- /dev/null
+[main]
+host = https://www.transifex.com
+
+[seafile-client.master]
+file_filter = i18n/seafile_<lang>.ts
+source_file = i18n/seafile_en.ts
+source_lang = en
+type = TS
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"/>
+ </dependentAssembly>
+ </dependency>
+</assembly>
\ No newline at end of file
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
+
+PROJECT(seafile-client)
+SET(SEAFILE_CLIENT_VERSION_MAJOR 7)
+SET(SEAFILE_CLIENT_VERSION_MINOR 0)
+SET(SEAFILE_CLIENT_VERSION_PATCH 8)
+SET(PROJECT_VERSION "${SEAFILE_CLIENT_VERSION_MAJOR}.${SEAFILE_CLIENT_VERSION_MINOR}.${SEAFILE_CLIENT_VERSION_PATCH}")
+ADD_DEFINITIONS(-DSEAFILE_CLIENT_VERSION=${PROJECT_VERSION})
+INCLUDE(FindPkgConfig)
+
+## Build crash repoter on release build as default
+IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+ SET(CMAKE_BUILD_TYPE Debug)
+ENDIF()
+
+# CMake's builtin UNIX variable is true on Mac/Linux/BSD, but sometimes we want
+# to detect for LINUX.
+IF (UNIX AND NOT APPLE)
+ SET(LINUX TRUE)
+ENDIF()
+
+IF (APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
+ SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.9")
+ENDIF()
+
+FIND_PROGRAM(git_executable NAMES git git.exe git.cmd)
+IF (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git AND NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+ EXECUTE_PROCESS(COMMAND
+ ${git_executable} rev-list HEAD --count
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ OUTPUT_VARIABLE SEAFILE_CLIENT_REVISION
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ ADD_DEFINITIONS(-DSEAFILE_CLIENT_REVISION=${SEAFILE_CLIENT_REVISION})
+ENDIF()
+
+SET(PATH_TO_BREAKPAD_ROOT CACHE "Path to breakpad's root" "")
+
+OPTION(BUILD_TESTING "Build Test" OFF)
+
+OPTION(BUILD_DOCS "Build Documents" OFF)
+
+OPTION(BUILD_SHIBBOLETH_SUPPORT "Build Shibboleth support" OFF)
+
+option(BUILD_ENABLE_WARNINGS "Enable compiler warnings." ON)
+
+option(BUILD_SPARKLE_SUPPORT "Build Sparkle support" OFF)
+IF (BUILD_SPARKLE_SUPPORT)
+ ADD_DEFINITIONS(-DHAVE_SPARKLE_SUPPORT)
+ IF (LINUX)
+ message(FATAL_ERROR "Sparkle Support is not available for linux." )
+ ENDIF()
+ SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/auto-update-service.h)
+ SET(platform_specific_sources ${platform_specific_sources} src/auto-update-service.cpp)
+ IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+ ADD_DEFINITIONS(-DSEAFILE_SPARKLE_DEBUG)
+ ENDIF()
+ENDIF()
+
+MESSAGE("Build type: ${CMAKE_BUILD_TYPE}")
+
+## build in PIC mode
+IF (NOT WIN32)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+ENDIF()
+
+## Setup warnings ouput if enabled
+## but don't warning on unsupported warnings
+if(BUILD_ENABLE_WARNINGS)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter -Woverloaded-virtual")
+ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unknown-warning-option")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option -Wno-inconsistent-missing-override")
+ endif()
+endif()
+
+## color diagnostics fix
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fcolor-diagnostics")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER}
+ -dumpversion OUTPUT_VARIABLE GCC_VERSION)
+ if(GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdiagnostics-color=always")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
+ endif()
+endif()
+
+IF (WIN32)
+ CONFIGURE_FILE(
+ ${CMAKE_SOURCE_DIR}/seafile-applet.rc.in
+ ${CMAKE_BINARY_DIR}/seafile-applet.rc
+ )
+ SET(EXTRA_LIBS ${EXTRA_LIBS} psapi ws2_32 shlwapi mpr crypt32)
+ SET(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_BINARY_DIR}/seafile-applet.rc)
+ IF (${CMAKE_BUILD_TYPE} MATCHES Release)
+ SET(GUI_TYPE WIN32)
+ ENDIF()
+ SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/ext-handler.h)
+ SET(platform_specific_sources ${platform_specific_sources} src/ext-handler.cpp)
+ IF (BUILD_SPARKLE_SUPPORT)
+ IF(NOT EXISTS "${CMAKE_SOURCE_DIR}/WinSparkle.lib")
+ message(FATAL_ERROR "File ${CMAKE_SOURCE_DIR}/WinSparkle.lib not found in current directory. Please setup winsparkle correctly." )
+ ENDIF()
+ SET(SPARKLE_LIBS ${CMAKE_SOURCE_DIR}/WinSparkle.lib)
+ ENDIF()
+
+ELSEIF (LINUX)
+ INCLUDE_DIRECTORIES(${QT_QTDBUS_INCLUDE_DIR})
+ LINK_DIRECTORIES(${QT_QTDBUS_LIBRARIES})
+ SET(EXTRA_LIBS ${EXTRA_LIBS} ${QT_QTDBUS_LIBRARIES})
+ELSEIF (APPLE)
+ IF (BUILD_SPARKLE_SUPPORT)
+ SET(platform_specific_sources ${platform_specific_sources} src/mac-sparkle-support.mm)
+ SET_SOURCE_FILES_PROPERTIES(src/mac-sparkle-support.mm
+ PROPERTIES COMPILE_FLAGS -fobjc-arc)
+
+ SET(SPARKLE_FRAMEWORK /usr/local/Sparkle.framework)
+ IF(NOT EXISTS "${SPARKLE_FRAMEWORK}")
+ message(FATAL_ERROR "File ${SPARKLE_FRAMEWORK} not found. Please setup it correctly.")
+ ENDIF()
+ INCLUDE_DIRECTORIES(${SPARKLE_FRAMEWORK}/Headers)
+ SET(EXTRA_LIBS ${EXTRA_LIBS} ${SPARKLE_FRAMEWORK})
+ ENDIF()
+
+ SET(platform_specific_sources ${platform_specific_sources} src/application.cpp)
+ ## Enforce ARC for this file, since ARC is only supported after the objc
+ ## runtime changes in os x 10.10
+ SET_SOURCE_FILES_PROPERTIES(src/utils/utils-mac.mm
+ PROPERTIES COMPILE_FLAGS -fobjc-arc)
+
+ FIND_LIBRARY(COCOA_LIBRARY Cocoa)
+ MARK_AS_ADVANCED (COCOA_LIBRARY)
+ FIND_LIBRARY(Sec_LIBRARY Security)
+ MARK_AS_ADVANCED (Sec_LIBRARY)
+ SET(EXTRA_LIBS ${EXTRA_LIBS} ${COCOA_LIBRARY} ${Sec_LIBRARY})
+ENDIF()
+
+IF(APPLE)
+ ADD_DEFINITIONS(-DHAVE_FINDER_SYNC_SUPPORT)
+ SET(platform_specific_moc_headers ${platform_specific_moc_headers} src/finder-sync/finder-sync-host.h)
+ SET(platform_specific_sources ${platform_specific_sources}
+ src/finder-sync/finder-sync.cpp src/finder-sync/finder-sync-listener.mm
+ src/finder-sync/finder-sync-host.cpp)
+ SET_SOURCE_FILES_PROPERTIES(src/finder-sync/finder-sync-listener.mm
+ PROPERTIES COMPILE_FLAGS -fobjc-arc)
+ENDIF()
+
+####################
+###### BEGIN: QT configuration
+####################
+SET(QT_VERSION_MAJOR 5)
+
+# Qt 5.6.0 removes QtWebKit, we need to use QtWebEnigne. First we detect the
+# current qt version, then use proper name based on the version. However we
+# have to keep using QtWebKit on windows because QtWebEngine can't be
+# compiled in msys2/mingw (QtWebEnigne is based on chrome, which has to be
+# compiled with MSVC.)
+FIND_PROGRAM(qmake_executable NAMES qmake qmake.exe)
+EXECUTE_PROCESS(COMMAND
+ bash -c "${qmake_executable} --version | grep -iE '^using qt version [0-9.]+' | awk '{print $4}'"
+ OUTPUT_VARIABLE DETECTED_QT_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+MESSAGE("qt5 version: ${DETECTED_QT_VERSION}")
+IF(WIN32 OR DETECTED_QT_VERSION VERSION_LESS 5.6.0)
+ ADD_DEFINITIONS(-DSEAFILE_USE_WEBKIT)
+ SET(WEBKIT_NAME "WebKit")
+ SET(WEBKIT_WIDGETS_NAME "WebKitWidgets")
+ELSE()
+ SET(WEBKIT_NAME "WebEngine")
+ SET(WEBENGINE_CORE "WebEngineCore")
+ SET(WEBKIT_WIDGETS_NAME "WebEngineWidgets")
+ SET(SHIB_EXTRA_HEADER "src/shib/shib-helper.h")
+ENDIF()
+
+SET(USE_QT_LIBRARIES
+ Core Gui Widgets LinguistTools Network
+ )
+IF (BUILD_SHIBBOLETH_SUPPORT)
+ SET(USE_QT_LIBRARIES ${USE_QT_LIBRARIES} ${WEBENGINE_CORE} ${WEBKIT_NAME} ${WEBKIT_WIDGETS_NAME})
+ ADD_DEFINITIONS(-DHAVE_SHIBBOLETH_SUPPORT)
+ENDIF()
+
+IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
+ SET(USE_QT_LIBRARIES ${USE_QT_LIBRARIES} "DBus")
+ENDIF()
+
+FIND_PACKAGE(Qt5 REQUIRED ${USE_QT_LIBRARIES})
+SET(QT_LUPDATE_EXECUTABLE ${Qt5_LUPDATE_EXECUTABLE})
+# from QT 5.4.0 Changelog
+# The Qt binary packages are now configured with C++11 enabled.
+# this requires your gcc compiler newer than 4.8.1 or clang newer than 3.3
+
+if (CYGWIN OR MINGW)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
+else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+endif()
+
+# for OS X, we requires libc++ instead
+if (APPLE)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ SET(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
+ SET(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
+endif()
+
+ADD_DEFINITIONS(-DQUAZIP_STATIC)
+
+# MOC FILES
+SET(moc_headers
+ src/seafile-applet.h
+ src/account-mgr.h
+ src/configurator.h
+ src/daemon-mgr.h
+ src/auto-login-service.h
+ src/repo-service.h
+ src/repo-service-helper.h
+ src/events-service.h
+ src/avatar-service.h
+ src/open-local-helper.h
+ src/server-status-service.h
+ src/account-info-service.h
+ src/customization-service.h
+ src/message-poller.h
+ src/network-mgr.h
+ src/settings-mgr.h
+ src/traynotificationwidget.h
+ src/traynotificationmanager.h
+ src/log-uploader.h
+ src/api/api-client.h
+ src/api/api-request.h
+ src/api/requests.h
+ src/rpc/rpc-client.h
+ src/rpc/rpc-server.h
+ src/ui/main-window.h
+ src/ui/init-seafile-dialog.h
+ src/ui/login-dialog.h
+ src/ui/account-settings-dialog.h
+ src/ui/check-repo-root-perm-dialog.h
+ src/ui/create-repo-dialog.h
+ src/ui/repo-detail-dialog.h
+ src/ui/settings-dialog.h
+ src/ui/download-repo-dialog.h
+ src/ui/cloud-view.h
+ src/ui/tray-icon.h
+ src/ui/about-dialog.h
+ src/ui/repo-tree-model.h
+ src/ui/repo-tree-view.h
+ src/ui/repo-item-delegate.h
+ src/ui/clone-tasks-dialog.h
+ src/ui/clone-tasks-table-model.h
+ src/ui/clone-tasks-table-view.h
+ src/ui/server-status-dialog.h
+ src/ui/search-tab.h
+ src/ui/search-tab-items.h
+ src/ui/init-vdrive-dialog.h
+ src/ui/uninstall-helper-dialog.h
+ src/ui/ssl-confirm-dialog.h
+ src/ui/private-share-dialog.h
+ src/ui/user-name-completer.h
+ src/ui/account-view.h
+ src/ui/seafile-tab-widget.h
+ src/ui/tab-view.h
+ src/ui/loading-view.h
+ src/ui/logout-view.h
+ src/ui/repos-tab.h
+ src/ui/starred-files-tab.h
+ src/ui/starred-files-list-view.h
+ src/ui/starred-files-list-model.h
+ src/ui/starred-file-item-delegate.h
+ src/ui/activities-tab.h
+ src/ui/events-list-view.h
+ src/ui/event-details-dialog.h
+ src/ui/event-details-tree.h
+ src/ui/set-repo-password-dialog.h
+ src/ui/sync-errors-dialog.h
+ src/ui/search-bar.h
+ src/ui/two-factor-dialog.h
+ src/filebrowser/file-browser-manager.h
+ src/filebrowser/file-browser-dialog.h
+ src/filebrowser/file-browser-requests.h
+ src/filebrowser/file-browser-search-tab.h
+ src/filebrowser/file-table.h
+ src/filebrowser/data-mgr.h
+ src/filebrowser/tasks.h
+ src/filebrowser/reliable-upload.h
+ src/filebrowser/progress-dialog.h
+ src/filebrowser/sharedlink-dialog.h
+ src/filebrowser/seafilelink-dialog.h
+ src/filebrowser/auto-update-mgr.h
+ src/filebrowser/transfer-mgr.h
+ src/filebrowser/thumbnail-service.h
+ third_party/QtAwesome/QtAwesome.h
+ third_party/quazip/quazipfile.h
+ ${platform_specific_moc_headers}
+)
+
+IF (APPLE)
+ SET(moc_headers ${moc_headers} src/application.h)
+ENDIF()
+
+IF (BUILD_SHIBBOLETH_SUPPORT)
+ SET(moc_headers ${moc_headers} src/shib/shib-login-dialog.h ${SHIB_EXTRA_HEADER})
+ENDIF()
+
+# UI FILES
+SET(ui_files
+ ui/about-dialog.ui
+ ui/login-dialog.ui
+ ui/account-settings-dialog.ui
+ ui/create-repo-dialog.ui
+ ui/repo-detail-dialog.ui
+ ui/settings-dialog.ui
+ ui/download-repo-dialog.ui
+ ui/init-seafile-dialog.ui
+ ui/cloud-view.ui
+ ui/clone-tasks-dialog.ui
+ ui/server-status-dialog.ui
+ ui/init-vdrive-dialog.ui
+ ui/uninstall-helper-dialog.ui
+ ui/ssl-confirm-dialog.ui
+ ui/private-share-dialog.ui
+ ui/account-view.ui
+ ui/two-factor-dialog.ui
+ ui/set-repo-password-dialog.ui
+ ${platform_specific_ui_files}
+)
+
+# RESOURCES
+SET(qrc_files
+ seafile-client.qrc
+ third_party/QtAwesome/QtAwesome.qrc
+)
+
+QT5_WRAP_UI(ui_output ${ui_files})
+
+# meta object compliation(moc)
+QT5_WRAP_CPP(moc_output ${moc_headers})
+
+# resources files
+QT5_ADD_RESOURCES(resources_ouput ${qrc_files})
+
+# MESSAGE("moc output: ${moc_output}")
+# MESSAGE("ui output: ${ui_output}")
+
+####################
+###### END: QT configuration
+####################
+
+####################
+###### BEGIN: pthread support is required explicitly on linux
+####################
+
+IF(NOT WIN32 AND NOT APPLE)
+ SET(CMAKE_THREAD_PREFER_PTHREAD ON)
+ INCLUDE(FindThreads)
+ LINK_LIBRARIES(${CMAKE_THREAD_LIBS_INIT})
+ENDIF(NOT WIN32 AND NOT APPLE)
+
+####################
+###### BEGIN: other libraries configuration
+####################
+FIND_PACKAGE(PkgConfig REQUIRED)
+
+PKG_CHECK_MODULES(SQLITE3 REQUIRED sqlite3>=3.0.0)
+
+PKG_CHECK_MODULES(JANSSON REQUIRED jansson>=2.0)
+
+PKG_CHECK_MODULES(LIBSEARPC REQUIRED libsearpc>=1.0)
+
+PKG_CHECK_MODULES(OPENSSL REQUIRED openssl>=0.98)
+
+PKG_CHECK_MODULES(LIBSEAFILE REQUIRED libseafile>=1.7)
+
+PKG_CHECK_MODULES(LIBEVENT REQUIRED libevent>=2.0)
+
+PKG_CHECK_MODULES(ZLIB REQUIRED zlib>=1.2)
+####################
+###### END: other libraries configuration
+####################
+
+
+# c/cpp sources
+SET(seafile_client_sources
+ src/i18n.cpp
+ src/main.cpp
+ src/seafile-applet.cpp
+ src/account.cpp
+ src/account-mgr.cpp
+ src/daemon-mgr.cpp
+ src/configurator.cpp
+ src/open-local-helper.cpp
+ src/message-poller.cpp
+ src/network-mgr.cpp
+ src/auto-login-service.cpp
+ src/repo-service.cpp
+ src/repo-service-helper.cpp
+ src/events-service.cpp
+ src/server-status-service.cpp
+ src/account-info-service.cpp
+ src/customization-service.cpp
+ src/avatar-service.cpp
+ src/settings-mgr.cpp
+ src/traynotificationwidget.cpp
+ src/traynotificationmanager.cpp
+ src/certs-mgr.cpp
+ src/log-uploader.cpp
+ src/sync-error-service.cpp
+ src/api/api-client.cpp
+ src/api/api-request.cpp
+ src/api/api-error.cpp
+ src/api/requests.cpp
+ src/api/server-repo.cpp
+ src/api/starred-file.cpp
+ src/api/event.cpp
+ src/api/commit-details.cpp
+ src/api/contact-share-info.cpp
+ src/rpc/rpc-client.cpp
+ src/rpc/rpc-server.cpp
+ src/rpc/local-repo.cpp
+ src/rpc/clone-task.cpp
+ src/rpc/sync-error.cpp
+ src/ui/about-dialog.cpp
+ src/ui/main-window.cpp
+ src/ui/init-seafile-dialog.cpp
+ src/ui/login-dialog.cpp
+ src/ui/account-settings-dialog.cpp
+ src/ui/check-repo-root-perm-dialog.cpp
+ src/ui/repo-detail-dialog.cpp
+ src/ui/settings-dialog.cpp
+ src/ui/create-repo-dialog.cpp
+ src/ui/download-repo-dialog.cpp
+ src/ui/tray-icon.cpp
+ src/ui/cloud-view.cpp
+ src/utils/uninstall-helpers.cpp
+ src/ui/repo-item.cpp
+ src/ui/repo-tree-model.cpp
+ src/ui/repo-tree-view.cpp
+ src/ui/repo-item-delegate.cpp
+ src/ui/clone-tasks-dialog.cpp
+ src/ui/clone-tasks-table-model.cpp
+ src/ui/clone-tasks-table-view.cpp
+ src/ui/server-status-dialog.cpp
+ src/ui/init-vdrive-dialog.cpp
+ src/ui/uninstall-helper-dialog.cpp
+ src/ui/search-tab.cpp
+ src/ui/search-tab-items.cpp
+ src/ui/ssl-confirm-dialog.cpp
+ src/ui/private-share-dialog.cpp
+ src/ui/user-name-completer.cpp
+ src/ui/proxy-style.cpp
+ src/ui/account-view.cpp
+ src/ui/seafile-tab-widget.cpp
+ src/ui/tab-view.cpp
+ src/ui/loading-view.cpp
+ src/ui/logout-view.cpp
+ src/ui/repos-tab.cpp
+ src/ui/starred-files-tab.cpp
+ src/ui/starred-files-list-view.cpp
+ src/ui/starred-files-list-model.cpp
+ src/ui/starred-file-item.cpp
+ src/ui/starred-file-item-delegate.cpp
+ src/ui/activities-tab.cpp
+ src/ui/events-list-view.cpp
+ src/ui/event-details-dialog.cpp
+ src/ui/event-details-tree.cpp
+ src/ui/set-repo-password-dialog.cpp
+ src/ui/sync-errors-dialog.cpp
+ src/ui/search-bar.cpp
+ src/ui/two-factor-dialog.cpp
+ src/filebrowser/file-browser-manager.cpp
+ src/filebrowser/file-browser-dialog.cpp
+ src/filebrowser/file-browser-requests.cpp
+ src/filebrowser/file-browser-search-tab.cpp
+ src/filebrowser/data-mgr.cpp
+ src/filebrowser/data-cache.cpp
+ src/filebrowser/file-table.cpp
+ src/filebrowser/seaf-dirent.cpp
+ src/filebrowser/reliable-upload.cpp
+ src/filebrowser/tasks.cpp
+ src/filebrowser/progress-dialog.cpp
+ src/filebrowser/sharedlink-dialog.cpp
+ src/filebrowser/seafilelink-dialog.cpp
+ src/filebrowser/auto-update-mgr.cpp
+ src/filebrowser/transfer-mgr.cpp
+ src/filebrowser/thumbnail-service.cpp
+ third_party/QtAwesome/QtAwesome.cpp
+ ${platform_specific_sources}
+)
+
+IF (BUILD_SHIBBOLETH_SUPPORT)
+ SET(seafile_client_sources ${seafile_client_sources} src/shib/shib-login-dialog.cpp)
+ENDIF()
+
+INCLUDE_DIRECTORIES(
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/third_party/QtAwesome
+ ${CMAKE_CURRENT_SOURCE_DIR}/third_party/quazip
+ )
+
+FOREACH(USE_QT_LIBRARY ${USE_QT_LIBRARIES})
+INCLUDE_DIRECTORIES(
+${Qt5${USE_QT_LIBRARY}_INCLUDE_DIRS}
+)
+ENDFOREACH()
+
+INCLUDE_DIRECTORIES(
+ ${OPENSSL_INCLUDE_DIRS}
+ ${LIBEVENT_INCLUDE_DIRS}
+ ${SQLITE3_INCLUDE_DIRS}
+ ${JANSSON_INCLUDE_DIRS}
+ ${LIBSEARPC_INCLUDE_DIRS}
+ ${LIBSEAFILE_INCLUDE_DIRS}
+)
+
+LINK_DIRECTORIES(
+ ${QT_LIBRARY_DIR}
+ ${OPENSSL_LIBRARY_DIRS}
+ ${LIBEVENT_LIBRARY_DIRS}
+ ${LIBSEAFILE_LIBRARY_DIRS}
+ ${LIBSEARPC_LIBRARY_DIRS}
+ ${SQLITE3_LIBRARRY_DIRS}
+ ${JANSSON_LIBRARRY_DIRS}
+ ${ZLIB_LIBRARRY_DIRS}
+)
+
+####################
+###### begin: lib
+####################
+
+# Helper Function to Add Seafile-Client Library
+# Usage:
+# ADD_SC_LIBRARY (name sources
+# MOC_HEADERS moc_headers
+# UI_FILES ui_files
+# DEPENDS part
+# LINK_LIBS libs
+# )
+FUNCTION(ADD_SC_LIBRARY name)
+ MESSAGE(STATUS "Found internal library: ${name}")
+ CMAKE_PARSE_ARGUMENTS(ARG
+ ""
+ ""
+ "MOC_HEADERS;UI_FILES;DEPENDS;LINK_LIBS"
+ ${ARGN})
+ IF(ARG_MOC_HEADERS)
+ QT5_WRAP_CPP(MOC_OUTPUT ${ARG_MOC_HEADERS})
+ ENDIF()
+ IF(ARG_UI_FILES)
+ QT5_WRAP_UI(UI_OUTPUT ${ARG_UI_FILES})
+ ENDIF()
+
+ ADD_LIBRARY(${name} STATIC ${ARG_UNPARSED_ARGUMENTS}
+ ${MOC_OUTPUT} ${UI_OUTPUT})
+
+ TARGET_LINK_LIBRARIES(${name} ${QT_LIBRARIES}
+ ${SQLITE3_LIBRARIES} ${JANSSON_LIBRARIES}
+ ${EXTRA_LIBS} -lglib-2.0 ${ARG_LINK_LIBS} ${ZLIB_LIBRARIES})
+ENDFUNCTION(ADD_SC_LIBRARY)
+
+# library utils
+LIST(APPEND utils_sources
+ src/utils/utils.cpp
+ src/utils/rsa.cpp
+ src/utils/api-utils.cpp
+ src/utils/paint-utils.cpp
+ src/utils/file-utils.cpp
+ src/utils/translate-commit-desc.cpp
+ src/utils/json-utils.cpp
+ src/utils/log.c
+ src/utils/stl.cpp
+ src/utils/seafile-error.cpp
+ )
+IF (WIN32)
+ LIST(APPEND utils_sources
+ src/utils/process-win.cpp
+ src/utils/registry.cpp
+ src/utils/utils-win.cpp
+ )
+ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "BSD")
+ LIST(APPEND utils_sources
+ src/utils/process-linux.cpp
+ )
+ELSEIF(APPLE)
+ LIST(APPEND utils_sources
+ src/utils/process-mac.cpp
+ src/utils/utils-mac.mm)
+ENDIF()
+
+ADD_SC_LIBRARY(utils ${utils_sources})
+
+# library quazip
+LIST(APPEND quazip_sources
+ third_party/quazip/JlCompress.cpp
+ third_party/quazip/quazip.cpp
+ third_party/quazip/quazipfile.cpp
+ third_party/quazip/quazipfileinfo.cpp
+ third_party/quazip/quaziodevice.cpp
+ third_party/quazip/quagzipfile.cpp
+ third_party/quazip/quazipnewinfo.cpp
+ third_party/quazip/quaadler32.cpp
+ third_party/quazip/quazipdir.cpp
+ third_party/quazip/quacrc32.cpp
+ third_party/quazip/qioapi.cpp
+ third_party/quazip/zip.c
+ third_party/quazip/unzip.c
+ )
+
+ADD_SC_LIBRARY(quazip ${quazip_sources})
+
+SET(SC_LIBS utils quazip)
+#SET(SC_LIBS utils)
+
+####################
+###### end: lib
+####################
+
+####################
+###### start: translations
+####################
+
+SET(SEAFILE_TRANSLATE_SOURCES ${seafile_client_sources} ${utils_sources} ${moc_output} ${ui_output})
+SET(LANGUAGES
+ ca
+ de_DE
+ en
+ es
+ es_AR
+ es_MX
+ fr_FR
+ he_IL
+ hu_HU
+ is
+ it
+ ko_KR
+ nl_BE
+ pl_PL
+ pt_BR
+ pt_PT
+ ru
+ sk_SK
+ uk
+ zh_CN
+ zh_TW
+ tr
+ nl_NL
+ lv
+ ja
+ sv
+ cs_CZ
+ el_GR
+ nb_NO
+ )
+
+SET(LANGUAGE_TS_FILES)
+SET(SEAFILE_TS_TARGETS)
+FOREACH(LANGUAGE ${LANGUAGES})
+ SET(TS_FILE "${PROJECT_SOURCE_DIR}/i18n/seafile_${LANGUAGE}.ts")
+ SET(LANGUAGE_TS_FILES ${LANGUAGE_TS_FILES} ${TS_FILE})
+ SET_SOURCE_FILES_PROPERTIES(${TS_FILE} PROPERTIES OUTPUT_LOCATION "${PROJECT_SOURCE_DIR}/i18n")
+
+ SET(TS_TARGET "${LANGUAGE}_ts")
+ ADD_CUSTOM_TARGET(${TS_TARGET}
+ COMMAND ${QT_LUPDATE_EXECUTABLE} ${SEAFILE_TRANSLATE_SOURCES}
+ -ts "${PROJECT_SOURCE_DIR}/i18n/seafile_${LANGUAGE}.ts"
+ -I "${PROJECT_SOURCE_DIR}/src"
+ -locations none
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
+
+ SET(SEAFILE_TS_TARGETS ${SEAFILE_TS_TARGETS} ${TS_TARGET})
+
+ENDFOREACH(LANGUAGE ${LANGUAGES})
+
+QT5_ADD_TRANSLATION(qm_files ${LANGUAGE_TS_FILES})
+
+ADD_CUSTOM_TARGET(update-ts DEPENDS ${SEAFILE_TS_TARGETS})
+
+####################
+###### end: translations
+####################
+
+###################
+##### begin: doxygen
+##################
+FIND_PACKAGE(Doxygen)
+
+IF (DOXYGEN_FOUND)
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in
+ ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
+
+ ADD_CUSTOM_TARGET(doxygen
+ COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating doxygen documentation." VERBATIM)
+
+ IF(BUILD_DOCS)
+ ADD_CUSTOM_TARGET(doxygen ALL)
+ ENDIF()
+ENDIF()
+
+###################
+##### end: doxygen
+##################
+
+####################
+###### begin: crash reporter
+####################
+
+# if you haven't installed it, please visit
+# https://code.google.com/p/google-breakpad/ to get a copy of it
+# or run the script build_breakpad.sh under the scripts directory
+
+## set up our crash reporter: breakpad
+
+IF (WIN32)
+FIND_LIBRARY(BREAKPAD_LIBRARY breakpad)
+FIND_LIBRARY(BREAKPAD_CLIENT_LIBRARY breakpad_client)
+MESSAGE(STATUS "Found library: ${BREAKPAD_LIBRARY}")
+MESSAGE(STATUS "Found library: ${BREAKPAD_CLIENT_LIBRARY}")
+SET(seafile_client_sources ${seafile_client_sources} src/crash-handler.cpp)
+ADD_DEFINITIONS(-DSEAFILE_CLIENT_HAS_CRASH_REPORTER)
+SET(EXTRA_LIBS ${EXTRA_LIBS} ${BREAKPAD_LIBRARY} ${BREAKPAD_CLIENT_LIBRARY})
+ENDIF()
+
+####################
+###### end: crash reporter
+####################
+
+####################
+###### start: freedesktop files
+####################
+
+if(NOT WIN32)
+install(DIRECTORY
+ ${CMAKE_SOURCE_DIR}/data/icons/16x16
+ ${CMAKE_SOURCE_DIR}/data/icons/22x22
+ ${CMAKE_SOURCE_DIR}/data/icons/24x24
+ ${CMAKE_SOURCE_DIR}/data/icons/32x32
+ ${CMAKE_SOURCE_DIR}/data/icons/48x48
+ ${CMAKE_SOURCE_DIR}/data/icons/128x128
+ ${CMAKE_SOURCE_DIR}/data/icons/scalable
+ DESTINATION share/icons/hicolor
+)
+
+install(FILES
+ ${CMAKE_SOURCE_DIR}/data/seafile.desktop
+ DESTINATION share/applications
+)
+
+install(FILES
+ ${CMAKE_SOURCE_DIR}/data/icons/128x128/apps/seafile.png
+ DESTINATION share/pixmaps
+)
+
+endif()
+
+####################
+###### end: freedesktop files
+####################
+
+ADD_EXECUTABLE(seafile-applet ${GUI_TYPE}
+ ${seafile_client_sources}
+ ${moc_output}
+ ${ui_output}
+ ${resources_ouput}
+ ${EXTRA_SOURCES}
+)
+
+INSTALL(TARGETS seafile-applet DESTINATION bin)
+
+TARGET_LINK_LIBRARIES(seafile-applet
+ ${SPARKLE_LIBS}
+ ${SC_LIBS}
+ ${QT_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ ${LIBEVENT_LIBRARIES}
+ ${SQLITE3_LIBRARIES}
+ ${JANSSON_LIBRARIES}
+ ${LIBSEARPC_LIBRARIES}
+ ${LIBSEAFILE_LIBRARIES}
+ ${ZLIB_LIBRARIES}
+ ${EXTRA_LIBS}
+)
+
+target_link_libraries(seafile-applet Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Network)
+IF (BUILD_SHIBBOLETH_SUPPORT)
+target_link_libraries(seafile-applet Qt5::${WEBKIT_NAME} Qt5::${WEBKIT_WIDGETS_NAME})
+ENDIF()
+
+## QtBus
+IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux" OR ${CMAKE_SYSTEM_NAME} MATCHES "BSD")
+ target_link_libraries(seafile-applet Qt5::DBus)
+ENDIF()
+
+### Xcode-related, build as a osx bundle
+IF(CMAKE_GENERATOR STREQUAL Xcode)
+ ADD_DEFINITIONS(-DXCODE_APP)
+ SET_TARGET_PROPERTIES(seafile-applet PROPERTIES
+ MACOSX_BUNDLE true
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
+ )
+ FIND_PROGRAM(seaf-daemon seaf-daemon)
+ SET(RESOURCES_DIR ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/seafile-applet.app/Contents/Resources)
+ ADD_CUSTOM_COMMAND(TARGET seafile-applet
+ POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${RESOURCES_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy seafile.icns ${RESOURCES_DIR}/.
+ COMMAND ${CMAKE_COMMAND} -E copy ${seaf-daemon} ${RESOURCES_DIR}/.
+ )
+ SET(CMAKE_XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS "YES")
+ SET(CMAKE_XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym")
+ SET(CMAKE_XCODE_ATTRIBUTE_GCC_ENABLE_PASCAL_STRINGS "NO")
+ SET(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES")
+ SET(CMAKE_XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "TRUE")
+ENDIF()
+
+SET(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${PROJECT_VERSION})
+ADD_CUSTOM_TARGET(dist
+ COMMAND ${git_executable} archive -v --prefix=${ARCHIVE_NAME}/ HEAD
+ | gzip > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.gz
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+
+### Test related
+IF (BUILD_TESTING)
+ MACRO(ADD_QTEST testname)
+ QT5_WRAP_CPP(${testname}_MOCHEADER tests/${testname}.h)
+
+ SET(${testname}_SRCS tests/${testname}.cpp ${${testname}_MOCHEADER})
+
+ ADD_EXECUTABLE(${testname} ${${testname}_SRCS})
+
+ TARGET_LINK_LIBRARIES(${testname} ${QT_LIBRARIES}
+ ${QTESTLIB} ${SQLITE3_LIBRARIES} ${JANSSON_LIBRARIES}
+ ${EXTRA_LIBS} -lglib-2.0 ${SC_LIBS} ${ZLIB_LIBRARIES})
+ SET_TARGET_PROPERTIES(${testname} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/tests )
+
+ INCLUDE_DIRECTORIES(${Qt5Test_INCLUDE_DIRS})
+
+ QT5_USE_MODULES(${testname} ${USE_QT_LIBRARIES} Test)
+
+ ADD_TEST(${testname} ${CMAKE_CURRENT_BINARY_DIR}/tests/${testname})
+
+ ENDMACRO(ADD_QTEST)
+
+ ENABLE_TESTING()
+ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/tests)
+ ADD_QTEST(test_server-info)
+ ADD_QTEST(test_utils)
+ ADD_QTEST(test_file-utils)
+ ADD_QTEST(test_stl)
+ENDIF()
--- /dev/null
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Seafile Client"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR/seafile.ico
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = ../
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/src \
+ @CMAKE_CURRENT_SOURCE_DIR@/README.md
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = .
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = com.seafile.seafile-applet
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH = third_party/QtAwesome
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>seafile-applet</string>
+ <key>CFBundleGetInfoString</key>
+ <string>Seafile Client Application</string>
+ <key>CFBundleIconFile</key>
+ <string>seafile</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.seafile.seafile-client</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleName</key>
+ <string>Seafile</string>
+ <key>CFBundleShortVersionString</key>
+ <string>7.0.8</string>
+ <key>CFBundleVersion</key>
+ <string>7.0.8</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>com.seafile.seafile-client</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>seafile</string>
+ </array>
+ </dict>
+ </array>
+ <key>LSApplicationCategoryType</key>
+ <string>public.app-category.utilities</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.7</string>
+ <key>LSMinimumSystemVersionByArchitecture</key>
+ <dict>
+ <key>x86_64</key>
+ <string>10.7.0</string>
+ </dict>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2014 海文互知. All rights reserved.</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+ <key>NSHighResolutionCapable</key>
+ <string>True</string>
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <string>True</string>
+ <!-- For Sparkle Framework -->
+ <key>SUFeedURL</key>
+ <string>https://www.seafile.com/api/client-updates/seafile-client-mac/appcast.xml</string>
+ <key>CFBundleLocalizations</key>
+ <!-- The CFBundleLocalizations would determinte the display language used by sparkle AutoUpdate.app -->
+ <!-- We must list all languages supported by Sparkle here -->
+ <!-- Sparkle would choose one based on current system language -->
+ <!-- See https://github.com/sparkle-project/Sparkle/issues/238#issuecomment-11927292 -->
+ <array>
+ <string>ar</string>
+ <string>ca</string>
+ <string>cs</string>
+ <string>da</string>
+ <string>de</string>
+ <string>el</string>
+ <string>en</string>
+ <string>es</string>
+ <string>fi</string>
+ <string>fr</string>
+ <string>he</string>
+ <string>is</string>
+ <string>it</string>
+ <string>ja</string>
+ <string>ko</string>
+ <string>nb</string>
+ <string>nl</string>
+ <string>pl</string>
+ <string>pt_BR</string>
+ <string>pt_PT</string>
+ <string>ro</string>
+ <string>ru</string>
+ <string>sk</string>
+ <string>sl</string>
+ <string>sv</string>
+ <string>th</string>
+ <string>tr</string>
+ <string>uk</string>
+ <string>zh_CN</string>
+ <string>zh_TW</string>
+ </array>
+</dict>
+</plist>
--- /dev/null
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and
+distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright
+owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities
+that control, are controlled by, or are under common control with that entity.
+For the purposes of this definition, "control" means (i) the power, direct or
+indirect, to cause the direction or management of such entity, whether by
+contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising
+permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including
+but not limited to software source code, documentation source, and configuration
+files.
+
+"Object" form shall mean any form resulting from mechanical transformation or
+translation of a Source form, including but not limited to compiled object code,
+generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made
+available under the License, as indicated by a copyright notice that is included
+in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that
+is based on (or derived from) the Work and for which the editorial revisions,
+annotations, elaborations, or other modifications represent, as a whole, an
+original work of authorship. For the purposes of this License, Derivative Works
+shall not include works that remain separable from, or merely link (or bind by
+name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version
+of the Work and any modifications or additions to that Work or Derivative Works
+thereof, that is intentionally submitted to Licensor for inclusion in the Work
+by the copyright owner or by an individual or Legal Entity authorized to submit
+on behalf of the copyright owner. For the purposes of this definition,
+"submitted" means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems, and
+issue tracking systems that are managed by, or on behalf of, the Licensor for
+the purpose of discussing and improving the Work, but excluding communication
+that is conspicuously marked or otherwise designated in writing by the copyright
+owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
+of whom a Contribution has been received by Licensor and subsequently
+incorporated within the Work.
+
+2. Grant of Copyright License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the Work and such
+Derivative Works in Source or Object form.
+
+3. Grant of Patent License.
+
+Subject to the terms and conditions of this License, each Contributor hereby
+grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
+irrevocable (except as stated in this section) patent license to make, have
+made, use, offer to sell, sell, import, and otherwise transfer the Work, where
+such license applies only to those patent claims licensable by such Contributor
+that are necessarily infringed by their Contribution(s) alone or by combination
+of their Contribution(s) with the Work to which such Contribution(s) was
+submitted. If You institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work or a
+Contribution incorporated within the Work constitutes direct or contributory
+patent infringement, then any patent licenses granted to You under this License
+for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution.
+
+You may reproduce and distribute copies of the Work or Derivative Works thereof
+in any medium, with or without modifications, and in Source or Object form,
+provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute,
+all copyright, patent, trademark, and attribution notices from the Source form
+of the Work, excluding those notices that do not pertain to any part of the
+Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any
+Derivative Works that You distribute must include a readable copy of the
+attribution notices contained within such NOTICE file, excluding those notices
+that do not pertain to any part of the Derivative Works, in at least one of the
+following places: within a NOTICE text file distributed as part of the
+Derivative Works; within the Source form or documentation, if provided along
+with the Derivative Works; or, within a display generated by the Derivative
+Works, if and wherever such third-party notices normally appear. The contents of
+the NOTICE file are for informational purposes only and do not modify the
+License. You may add Your own attribution notices within Derivative Works that
+You distribute, alongside or as an addendum to the NOTICE text from the Work,
+provided that such additional attribution notices cannot be construed as
+modifying the License.
+You may add Your own copyright statement to Your modifications and may provide
+additional or different license terms and conditions for use, reproduction, or
+distribution of Your modifications, or for any such Derivative Works as a whole,
+provided Your use, reproduction, and distribution of the Work otherwise complies
+with the conditions stated in this License.
+
+5. Submission of Contributions.
+
+Unless You explicitly state otherwise, any Contribution intentionally submitted
+for inclusion in the Work by You to the Licensor shall be under the terms and
+conditions of this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify the terms of
+any separate license agreement you may have executed with Licensor regarding
+such Contributions.
+
+6. Trademarks.
+
+This License does not grant permission to use the trade names, trademarks,
+service marks, or product names of the Licensor, except as required for
+reasonable and customary use in describing the origin of the Work and
+reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty.
+
+Unless required by applicable law or agreed to in writing, Licensor provides the
+Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
+including, without limitation, any warranties or conditions of TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
+solely responsible for determining the appropriateness of using or
+redistributing the Work and assume any risks associated with Your exercise of
+permissions under this License.
+
+8. Limitation of Liability.
+
+In no event and under no legal theory, whether in tort (including negligence),
+contract, or otherwise, unless required by applicable law (such as deliberate
+and grossly negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License or
+out of the use or inability to use the Work (including but not limited to
+damages for loss of goodwill, work stoppage, computer failure or malfunction, or
+any and all other commercial damages or losses), even if such Contributor has
+been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability.
+
+While redistributing the Work or Derivative Works thereof, You may choose to
+offer, and charge a fee for, acceptance of support, warranty, indemnity, or
+other liability obligations and/or rights consistent with this License. However,
+in accepting such obligations, You may act only on Your own behalf and on Your
+sole responsibility, not on behalf of any other Contributor, and only if You
+agree to indemnify, defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason of your
+accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+
+To apply the Apache License to your work, attach the following boilerplate
+notice, with the fields enclosed by brackets "[]" replaced with your own
+identifying information. (Don't include the brackets!) The text should be
+enclosed in the appropriate comment syntax for the file format. We also
+recommend that a file or class name and description of purpose be included on
+the same "printed page" as the copyright notice for easier identification within
+third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+======================================================================
+For QtAwesome (third_party/QtAwesome):
+======================================================================
+
+All files in QtAwesome are
+Copyright 2013-2015 Reliable Bits Software by Blommers IT. All Rights Reserved. Author Rick Blommers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+## seafile-client [](http://travis-ci.org/haiwen/seafile-client)
+
+[Seafile](https://seafile.com) desktop client.
+
+## BUILD ##
+
+### Prerequisites ###
+
+- Qt5
+- cmake
+- [libsearpc](https://github.com/haiwen/libsearpc)
+- [seafile](https://github.com/haiwen/seafile)
+
+### INSTALL ###
+
+```
+cmake .
+make
+make install
+```
+
+> Qt 5.2 or higher is required
+
+Ubuntu users can install seafile client from this [PPA](https://code.launchpad.net/~seafile/+archive/ubuntu/seafile-client)
+
+### INSTALL with Qt5 ###
+
+```
+cmake .
+make
+make install
+```
+
+> Qt 5.5 or higher is recommanded but not required
+
+## Internationalization
+
+You are welcome to add translation in your language.
+
+### Contribute your translation
+
+Please submit translations via Transifex: https://www.transifex.com/projects/p/seafile-client/
+
+Steps:
+
+1. Create a free account on Transifex (https://www.transifex.com/).
+2. Send a request to join the language translation.
+3. After accepted by the project maintainer, then you can translate online.
--- /dev/null
+## C++ Coding Style
+
+Mainly borrowed from [google c++ style coding style](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml)
+
+### Naming Conventions
+
+#### Member Vairables
+
+Lower case words seprated by underscores, and ends with an underscore, e.g. `repos_list_`, `context_menu_`
+
+#### Variables in Qt Ui Files
+
+Camel case starts with a "m", e.g. `mUserNameText`, `mServerAddr`
+
+#### Functions
+
+Camel case, e.g. `showRepos`
+
+#### Setter and Getter
+
+- setter: `setRepoName()`
+- getter: `repoName()`
+
+#### Constants
+
+Camel case starts with "k", e.g. :
+
+ const int kRepoRefreshInterval = 1000;
+ const char *kDefaultName = "seafile";
+
+Use constants variables instead of macros to define constants.
+
+### Invoking functions
+
+- constant function parameter must be passed by object reference
+- No `this->` when invoking member functions.
+
+### Others
+
+- no source file scope static variable/function, use anonymous namespace
+- use forward declaration when possible, instead of including unnecessary header files
+- Never use exceptions
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="svg3828"
+ width="170.66667"
+ height="170.66667"
+ viewBox="0 0 170.66667 170.66667"
+ sodipodi:docname="seafile-new.svg"
+ inkscape:version="0.92.2 (5c3e80d, 2017-08-06)">
+ <metadata
+ id="metadata3834">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3832" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="640"
+ inkscape:window-height="480"
+ id="namedview3830"
+ showgrid="false"
+ inkscape:zoom="1.3828125"
+ inkscape:cx="85.333336"
+ inkscape:cy="85.333336"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg3828" />
+ <image
+ width="170.66667"
+ height="170.66667"
+ preserveAspectRatio="none"
+ style="image-rendering:optimizeQuality"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA
+B3RJTUUH3gENCCIF8iHFhQAAIQpJREFUeNrtnXl8HMW1779V3T0arWNt1uJ9kbG8YwwECJsNgdhg
+lgAJPG7s3OB8/LiY9wLcm1x4yQNDcrm55MMn5kJICAQ/SFgcVmPCJsALEBYb27KRF3mRZUuyVku2
+pJGmu+v90SONxtJIM6MZSQb9Pp/62Orprjp1zulTp06dqoZhDGMYwxjGMIYxjGF84yAGm4BYQimF
+EIEuHTt2bKTb7T5NKTVJSjkGyAOygDQhRJJSSgcQQphKqRagCagFKm3bLhdC7PN6vbtHjBhRHaqN
+Ux2ndE+6CqO5uXm8lHKBlPLbwNlCiMIYt1UCfGrb9ibbtouSk5MPnkzDqYhTjvIOhn/++ef6zJkz
+bxBCXCuEuBJwDTAp7UqptUqpl4uLi18888wzzVNRGU4Jarsy1uv1LhVC3CKEOC/y3kpAQighKQXY
+oOxoaPxIKfUnt9v99Mk0D2UMaQo7mHj8+PHZLpfrZ0KIG8PqktRBAt56RPNhOHEA4W1AtB6F9jrw
+tYJt+gWOoxBSByMRXJmoxByUOx1SJqCSR4M7A2ycZ1Dh0P18e3v7g6mpqduGuiIMSco6mNbS0nK1
+pmm/7n08F6DpYLYgar9A1G9D1O1ANOwAZYE7ERKSUC4XQtdB00CTjjWQ/u7bynnrLRssC2WaiPZ2
+aGsBbysIDZU+A5U5A5UxG5U1D/QksHpXCKVUiWVZdyclJb06VBVhSFHURfDXa5q2SgiRG5JsXUcc
+24OoeB9RuQHRVAqpI1DJqYhEN8rtBl133nLV91vbczPCKaaJ8HpRrV5E83E4fgyVNhmVdwEqfz5q
+xBQwQyuDUqrKsqzbk5KS1gw1RRgSlHQx9ee7XK5nhBDjerxRGgjvUcTBl5Blb4B9AjUiE1JTIDGx
+f8IOm2N+pWhtheMnEMfqQKZgj7sCNf57KHcO2L5Q/Sxrb2//p9TU1I1DRREGnwLg8OHDGVlZWS9I
+KS/p8QbNQFStR+59FnFsByorFzwecLnAjtxhiymkhPZ2aGxE1FahRszALrgZlXshWD0rgm3b79XW
+1n5/9OjR9YNL/CAqQBdzf5eu6//V402agSx7BVnyJ9DbIWskKiXZEXqcX/SIIQApESeaobYaTBd2
+4S3Y464JqQimaf5rUlLSQ4NpDQZNAaqqqkamp6d/2KODpxnI8jeQOx6BRA2VnQ2GEX/zHisIAT4f
+oqYGWi3sGSuwx1zRoyIopUoaGhouys3NrY6ipX5DDmRj7733HgBNTU03ZWRkHO0mfGkgGkvQ370W
+WfooalweKj8/4MydKlAKdB2Vn48al4csfRT93WsRjSUgjaBbhRCFGRkZR5uamm4CKCoqGlBSB8wC
+dDH5f9V1vft8XploX65E1H6MGj0OXB1v/JBwU/rTc8citPsQh8tQWedinf5LEHq3Oy3Lei4xMfGm
+gRwSBsQCKKX44osvkr1e795uwpcGsvoj9LcXAvtQkwrA6PrGq1O84PTF0J2+sQ/97YXI6o+6WQNN
+0270er17N2/enKwGyOINiJpVVFSMz8zM3CmESApuXaJ9eS+i/mPU6LGhQ7RfNyiFOHwIlXEu1un3
+dgs9K6Va6uvrp+fl5R2MNylx53hNTc08j8fzebdmvUfRP1qO8iQ4U7oo4u+nNIR0po6NbZjnPQ7u
+HE6e2jQ2Np6ZnZ39RTzJiOsQUFNTc1E34QsdUfsJ+vqbUPnpkJb6zRM+OH1OS0Xlp6OvvwlR+0k3
+v8Dj8XxeU1NzUTzJiJsFqKmpWeDxeN4LuqgZyL2rkQeeRo2ewNCbzA8WBOLwAewJS7ELlnSbLjY2
+Nl6SnZ0dl+lBXBSgsrLynMzMzI+DLmoG2rYHEQ3rUTm5p9a0biAgBOJoFSr9QqzZP++mBHV1defm
+5eV9EvNmY1mZUory8vLTcnNzdwX9oBloX/wfaCuGjAxn9W0Y3SEF1NdDwkyseQ90U4KqqqqpY8aM
+2R3LKWLMfAClFBs2bMjIyckpDvpBM9C+uBvMnZCe7o/dD/bUbIgW23Z4ZO50eKYFTxNzcnKKN2zY
+kBHLKWJMVKkjcOH1eg9LKUcFCf/L+8G7BdI8DI/54UJAUyO452Kd/osgS2DbdoXb7R4Vq2BRTCyA
+EILm5ua3goQvdeSuP0LLZ5CW5l+qZbiEVZTDs5bPHB7KwOxASpnf3Nz8VqyGgZgoQF1d3R2GYVzW
+RSUQFe8iq14Cj3/MV8MlomIr8GQgq15CVLxLV2NtGMZldXV1d8RCdv1SI6UUu3btKpw0adJXQZU2
+H0L7dBkqb8w3c44fSwiJqCzHOvsJVPLYoJ9KS0unFRYWlvTHGvTbjrS2tlZpmpbTeUHZ6B9cg8rN
+cjT5GxLdjRsUzhSxqhbz4lf8mc0OLMs6mpiYmBt95f0cAhoaGh4JEr5moH12Byo7PfDmD/p4eooX
+AGWjstPRPrsjaGagaVpOQ0PDIwOuAEoptm/fPi05Ofm2wFWBPLAG5BFnPtvhzAyXGBQcnsojDo+7
+mNXk5OTbtm3bNi3aqWHUBrq5uXmvYRiTOy/4GtE/uhGVncNwlC9OEAJRcxTz3OfA5em87PP5SpOT
+kwuiqTIqC1BRUbHM5XIFhK8Z6JvvQWXm+D1+hks8iq1QmTnoW+4JGgpcLtfkioqKZdHIMioL4PV6
+vVLKhE4tqngfcfgxSEyOtsphhA0Frc2o0bdi58/vvGrbdpvb7XZHWlvEFqC6uvq+rsJHasi9/w2J
+KYM37tsW2O1gtTs5+bY1BMbtOPoDiSnI0v8GqQXEIGXC0aNH741UnpG+rlpbW5sZmHcK5N6nEM1F
+Tn78gEGA8oGWjEj/FqSchkjIAekCuw3lrYITu1ANn4Lt9a+zf838EttGJS/ALvjnzr4ppUhISNAB
+KwJOho+qqqr/m5GRcW/nBWWib7wa5ckYuI4rC9x5iLE/Qnjm9H37sS9QZX+G9tqgOfTXAaKxAfP8
+V4ISSerq6u7Ny8u7L+w6ImnQ6/W2SSmdffhCopX8HrybIq0myt4Cdrsj+NwrIn5cVbyEKv8LaAlf
+I2OgwH0eVuGtdMRdbNtud7vdCeHWEPYrcfDgwR9rmhY4hEFZUPNGgJB4F9tETn8wKuEDiPzvIQtX
++vftDbY7H6sC1KxzZOGHpmmugwcP/jhsvoR7Y1NT02632z2l4zG5/zlk49pIqogedjti+oOQelr/
+6zq2FbXrPsdf+FpAYXuuxJ54Ix1K4fV696SlpYXFrLAswNq1a2ckJiZO6byg68jKVxiYKZ8NY26K
+jfABRsyB/Ks7mXXqQziy0AN+QGJi4pR169bNCOfpsBRg3rx5K7qGGkXFRjDsgZn2aB7EqOtjy7Kx
+S0AkDIEpXYyKYTsy8UMpxdy5c1fETAE8Hs8PA0/oyKq3QXcR9zFOWYixPwyDwigw9n/4HafBHsdj
+UHSXI5MuiSNBMuuPAmzYsOEiwzACESarHdH4aSAoEdeiIPuCuMhf5FzmBI+GgPxiwSfR+KkTCPPD
+MAz3xo0bL+q3AkycOPEHXc2/rCwCd+qAdEyMOD0uwverACJ1xhAQXoyKO9WRjR9KKSZMmNDnoVp9
+KkBaWtpVgbsNRO0mf0Al3uZfoVJi5PiFgEqd0gcNNlhtYLWClgTuXKcYHrDbwPLiTMEGW/rKyRyq
+3RS04TQtLW1xXzzQe/txxYoVY5KSknLtjmNYBIjGLxwLEB+R0NmQshDukXFqxw93jl+AJ70HlhdS
+C2DkxYgRcyFpTM/Pt9fBsW1QuwlV96kTZBrExTDRGLyNMCkpKff2228fs2rVqvJQz/SqAMuWLVsY
+5P3XbAYjxpE02weuDMg8CxJHO9alrQYaNhP33euNu0B1EZjlhezzEeOXQjiZVq5MGDkfRs5HWG2o
+8ueh/KVu274HDEYConYzKmMW4AwDy5YtW7hq1ao/hHqkVwXIyMiYH1AAgTi21d+5GGiAAlwexGk/
+Bc+s7r9P+FFceaX2/A5qPgShOc6mkYaY8xAkT4iuQi0BMX4JjLketfMBaNwZtFo3IJAG4thWVMZs
+QKGUIj09fT4QnQIkJyefE6hcRzTt8Mu+vwqgYMQsxIyVA8ugjtbLX4CjRY7wbQsy5iGm/yI2lWtJ
+iFm/Rh1+CfY/BTIhBvwKF8KRkdQ7j6oLkmEP6E0B3MnJyYHBT4Jo+gpcSfQbSeMGTfg07YL9qx3B
+2BbkXYYo+JeYNyNGfw/c+Y41GLCws3JkJHGOtgX8MnQD3p6eCDnIPv3003NklzV+0XQINEG/vVW7
+DTHr/gFiSA8s2nGvXyA2ZJ8XF+F3IuscxNQ7nBnDQM0GNOHIyg8pJU8//fScUCSGtABTp06dHZRp
+2nLIWXfuV8KnQORcAkZabBjcXIZq3AHNh8DX6DBAT4WkUYi0aXDSeog68AyYrYAAdy6i8GexoaM3
+5Cxw/IGqATr9S+iOrJLynD4rxdSpU2cD/+jp9pAK4PF4pgbNAFrK/Q5TP4hTPsiZ348KAGWiDj4H
+R9aCr8l5m4UImkGiFEr5QLgg/3LEhJsdxSh73mGQ3YaY/at4sL9HiCm3o2o+BetE/N0BoSFaylGc
+7bBLKTwez9RQt4dUALfbPTFQqUR4K/tPvO2D1ClRP64Ovwalf3QUEeF3sAimS+H8JvzjbsXfUeWv
+woiZgQDWmGsgIav/zI4AYupPUdt/Gf8posKRlZB0JIkkJCRMCnV7bwowOkC9Bq1HozP/tgkjpjmC
+r17vHLMecads1Ja7oGl3wAop0wkWeaY5e+b0ZCdvoPUoqnEnmM0B50smQNMeQDj3TIzvFLNHZM6D
+xFHgPRr/tlqP+vnkKEBiYuKoULeGVADDMAJhOIET9YpYAWwYdz1ikp/hBT9x6ohkM6MyUZ/8GNrr
+Ha22fZA8FjHxh5B9Xid5XSEATuxHHVoDle+B5naURoDImT9ogRox7nrUrt8R9wBXe10QUwzDyAl1
+ayhKNMMwgjI9RVtt5ISYrQHhd1YUWahUfXortNU7ArQtxLS7EGf/oVP4IZEyETHtZ4hznwFXFqCc
+gxbyLu0ve6NH7qXO2kKccbKsDMNIB3qMSoVUAF3vYqsFDuHR5LD3A2r3Y9ByxG81DMR5/w9yF0RW
+SWIu4tw/Oz6A7YOMeK4w9gEhEGmFUfAxwmK1nWwBkghh7XtTgOArti9yQrQEVOlT0TGr5TCUveT/
+QyHOfbJfjps4/T8g/7vxEWwEUCOm07HaGb+NMsGHS2maBiFkHcoHkFJKguIAKuy9Bl2rgQPPoxqK
+wTMtAvMvoPZzZ+w22xBzfw2u9H4zX0y/q9919BtJY5zDoOK5R+EkWfkDepErgGV1qUjZ0c0ChA6N
+u50SDTLnQtZZ8WPWAEMkZKCURVyXjU86lSUaBcA++VMsHatmAwm7HVEQ1abXoQvRcQx+HHkpgv09
+u5fP6oSyQ8o0ze6EDzQSMiEtqm3vQxd22wBEA4Nl5Zdlj62GsgDK5/NZmt97QOFfPWtnQJH9rYFt
+72S0VEDjLpS3FrDBlY5ImwSpk6OuUnnr/KHrOGqBDE7a8fl8HXlr3RBKAaz29vYTbrfb03lFSx6Q
+OWyAUwpSJvW/nmiaLn0Gyl6GtgYnaNThsCkbpUzn2uhFiCn/DEaE6XEnykB15FTGCVpy0J/t7e0n
+CLFjONQQYHu93roAR0DFOz/vZCgbkdB/zz8iVH+CevtyKH0GzBYnx6+rty6kP7wsoPxN1LtXovY9
+F1kb9dsdL10p8DU7wakY64Jyjwyq0+v11tOZIRCMUBbAbG5urgWcBSFlQ+JIaCyJLaW9d4OBPGNQ
+lTwK+1/0J3YSnomWLtjzJ1T9l4gzf9P3/bYPGooRM++C8dc51xqK4ch7qENrgzZ29AuJI4N455el
+2dOtISejx48fPxLgjoVy58c/gtW1IP1jb/yhtv4aDrzsCDQKOqnZgvr83/tup3wd5F8aED5A+kyY
+8VPEd9+B3Av9EVf6xTtHVgGLf/z48cOhaOpRAbKysuzq6uoDXU+gVMmjnBSqgUTjnrg3obY9CEfe
+619gRgio/gccfLn3+46VIM4IkQ0ldMScexCz73ayk6OFbaGSAot/Qgiqq6sPZGVl9WhOe+x1bW0t
++/bt29U1JYyUif4lWAauHP0oekaEAbXtQTj8dpcl5j6KbYPpBd8Jp9hW4Deho3asCtqeFQTfCcTs
+vq0Eoy9DzP65U09UfDMhNZDKIaVk3759u2tre7amIdX+iSee2B5kAdImD/zhS94GOBrzj2Q4/dn6
+IJS/DWhhxNYtMEbA9NsQl6xBLP4EMfdeSDxpWBQ6au/qnhs0UsInbsxCyL0gynUAy5GVH0IInnji
+iW2hmuotHpnV1NR01O12O0qiGWgf3oxorYyLQIJgeRH5F8OE70HG7JjHzdW230D5m90iZj3T0g7T
+b0VM8m+zs32oD5dAS2XPdOlJiMvW9p9I04t685KAUxpu3xLzsC56tvMbA16v105LS8sBejQBvXG2
+uaKiIvDpF9tCpc+Mv9l3pSMWvADzHoDM0+Mj/EPrcN78Pmgx2xDnPBwQPqA+ug1ajjqs6+mZ1jqI
+hfOquxGjL4uYfyp9ZpCvVlFRsRtoDtVMb9xtP3To0JbOYUDZqMwznBSvuHj9ClJGIy79GySPJh5Q
+234DZW8QltlXFhQug+x5gQrqdzilt+ekDo17Y0PwqAWRLcPbpiMj/xRQCMGhQ4e2ACFDuL0pgLVp
+06YNXR1BNfJbfg811q89jhd84ZNxETyA2v5bR/hCC48mPQUxZUlwHdX/8AeCentWoNqOxYbojJl+
+pzJMPlpe1MizOx+XUrJp06b19HJuYK/2deXKlR/4fF2SC1wpqLSC2MvfthAz/lePH1SOBdS238L+
+VwnL7Cuct2nS97tXZLaG0RcbEU3ia08wUoNnGn2Z/9QCcAVC0z6fj5UrV37YWxN9DbBH9+3bFwj/
+WSYq7yI6cwNimcEyblEMRR6A2vZbOPBKYDk7zJQqkdN9S51IK+h7CLTbIOfsKCgN2YMw6bZR+ReB
+FQj4lZaWlgBVUStAampqy+bNm4sCw4BCjbo05sOASJ8eH+Fvfxj2vxy+2e8otgmpY7tXOPZy6Dwq
+scfXHybe4GQyxQJWm19EYZr/UZfSMaRKKfnyyy+LUlNTW3prolcFOH78uHXnnXe+FOQHpI1z8vBj
+OAQo14jYMKwL1LaHofRv/u1sUdAVYoooLng8sIDTtVg+yDwdMSeGaWcNJWHTr5LHotLGBQQrJXfc
+ccdLx48f7zV82+ccq6ampnj37t0HOy+YPtT4a/3DQBSM7aGI9sbYMQ2/8PetiV74SP9Urwd4ChBX
+vg3jroDEbGfenzkLcfavEN/+XUz7wZEPwuyD7cjEDPhru3fvPlhTU1PcVxN9el3JycnH1q9f/3pB
+QcHtHalF9oSrkcUPx8zUqfodMcuQU9tXQemL/TvIQhpQsxmS83v+3UhBnP6vMaK4l77sf6Xjf73f
+aLVhT7g6QL6UrF+//vXk5ORjzc3NvT7apwVobm62li9f/mxQiph0O+NNzBxBoPyd/jNs+yrY89fA
+LuaoYxICVfpinMQaZl+KHw3b2VajLgUZeBlN02T58uXPNjc397l6F26Ybfcnn3wSWJlRJvZpSxFW
+a2x6KzT48qH+1VH8CGLPX2O37evYHqj8uP/1RIP6r2DXasLJHBZWK/ZpS0EFXlC/rMJKww5LAVwu
+1/H777//CcMIMFeNKEBlzkEoFZOCrwXevyU6hhU/CruedYJJMaJHCAM++TnE2D/pE4374INlCOkK
+i06VOQc1IpA4axgG999//xMul+t4OM1FMvTmbd++fdPUqVM71xpFw1foH/wY9MgWLEJCAamj4cLH
+wJ3Z9/22Dz5/AMr+3u1L27GBcCJ/858AzwDkJ5a+CFse8k81w/BfzDbMi59EpU/rvLRr1679s2bN
++jYQ1qpd2MdYpaWltTY2NiZce+21l3TmmafkI6s/R7TWxI4J7U1Q8jR4a5xTLnpShJZK543f+L+h
+6UB4q3rRQlmw9zlorYa0iZDgiW39tg8OroOP/w3K34soLUxlzsSe/hM6Yv+GYXD33Xf/5759+95t
+a2sLywOO1PkeX1JSsmnSpEmdKSfiRDn6W9eBnhhbxqCcOLjUwTPBCYuardBU5iRj6O4oyO8nPaYX
+XGmQNt5vcfrRvrKguQpOHHH6EqkSm62Yl/8NlRI4x2vfvn1HCgsLvw0cDLeaiFpNSUk5UVlZqd1w
+ww0BK+DORDRXIJr295PBPUBqTrpVW6PzBrY1AHbskicjpkd3BOetg9Yah6aoS60TUdWMiLfMA9hj
+L8eeeE3Q23/bbbf9uqys7O329vaws2mjUeFxn3322btz5swJeB62ifHafH91Uc69hxEmHB77rno/
+6EXYunXr3rPOOutSoCyS2iLOtkhKSipfunTpg0H5glLHOuPfB37n0DcRts/hdRfhSylZunTpg0lJ
+SeWRVhexArS0tNhfffXVG2vWrCnqmjNoT1iMypwT0zWC4dK9qMzZ2BMCh4ALIVizZk3RV1999UZL
+S0vEGymi9WIEcEF1dfVbI0aM6BKCasV4/TKGh4H4wbf4Xb8D7ODYsWPekSNHXg5sIArGRz1/SkpK
+qtm1a5d24403XtDpEEoDMmYgD7wW36nZNxFWG9b5q4JW/AzDYMmSJQ+WlZW94AvK3AkfUUvJ5/P5
+SkpK9s+cOfOswsLCMR2niai0cQizFVFbzPCHpGMEZWOfdjN2wfWdXr+UkldeeeXj++677x6fzxd1
+Fmp/JSSAC8vKyl7Ny8sLREg0A/3dHyHqd8agiW86FCpjOualf+5M9QaorKxsHDdu3NXAevox5vZb
+Om632z169OhlO3bsWCVP+oC08cZiZ848jOjhzsR3xetBl2zbZsaMGbcfPnz4Ca/X2499ZP0YAjpg
+mqZZX19/oLKyMu2aa66Z1/U4EnviVWh7XvDnqQ87hpFBgObCt+iVoBVOwzBYvnz5H4qKih4xTbOp
+v63EylNr+fLLL3fn5ORMO+ussyZ2dQrt8Veg7X0RZw4zCHw8FSEAoeFb+FLQ2oOu6zz++ONFDzzw
+wD1AxHP+UE3Fkuwz3n777dULFiyY1tUSiJYq9HXXMZD7/U9pCIm56G+opMB3i6SUFBUVfXXZZZct
+ATYTo9cpph6alFKzbfvizZs3/3nWrFmjg84ZbK3GWHddt0MMh3ESpIFv0d+cQx78EEKwffv2I2ec
+ccZSKeUHth27ffoxd9F1XTdM01y0c+fOP06ZMiU7SAnamzDevMFZ3BlGdyR48C180Vlx9EMIwZ49
+e2qmT5/+E13X15mmGdM3KC5zNMMw3D6fb/HOnTsfnTJlStbJJ47q7yxBNOyJ72mZpxKUjUqfgvmd
+1UEBtC7Cv80wjNd9Pl+/PP6eEBcJ+Hw+r67rr0+fPv1fiouLK4Omh0LDXPgC9oQrwWwb9Nj6oBez
+DXvClZgLXwgSvpSS4uLiyunTp9+m63pchA9xjtJomua2LOvyoqKihy6++OJJQZnFmoE88Cbapn8f
+vPX9wYYysc77D+wJC4OCPJqm8eGHH+5bsGDBXZqmvWVZ/TkzpnfENWCvlDKllPtWr169c8yYMafN
+mzdvVOfsQNkoz2TsKTcgj2xAeOv4xkQNlYVKG4+5aA0qcwZdD3QyDIOnnnrqs+uuu+5OKeW7th3f
+Nfa4r9gopWyg7PXXX99aXV2duWjRosIgn0B3YxfeBEJHVnw88F/bHGhY7VhzVmBd8F/dvicopWTF
+ihUv/+IXv7gH+FgpZUbXSPgYyFdOAAWzZs1a9s4779yWmZnpDlIEIaG1Fn3jzxBHP/cfjfJ1iRwJ
+sNpQuWdifvs/ITErKCYihKCurs77ne9855Ht27f/Cdg7UJ0fcJtrGEa2z+e7at26df+2cOHCgm6r
+mLqBLN+I9o+VTtLkqe4f2CYk52J965fYY84P2r/n5wdvvvnm3kWLFv3GMIxX+7OyFw0GZdAVQriV
+UucsWbLkfz7yyCPfS0xMlEHWABxF2Psa2paHnXN3TjVFsE1IzMSa+1Psgqu6CR6cA5xWrFjx0urV
+q38vhPhEKRU3Zy8UBtPrEkKI8Uqpq1977bXlixcvntJjToNuIA+8hdz2OKK+JA7p5zGG2YrKKMSe
+vRx7wuU9Ct4wDNauXbt38eLFvxdCvKqUOsggjXeD7nYLIRKVUmeff/75Nz355JM3TJ482dPtWwUA
+uoGoLUF+9Sxy/+t0Hsg0FGCbIAT2xMXY025GZRX2KHhd1yktLW285ZZbXtywYcNfhRCfKqVitMEy
+Ogy6AnTQoWnaSMuyLrz11lv/6Ze//OWl2dnZCUGfrAncCUIiD76F3L8OUf6+owzaQH2h2w+rHYRA
+jZmPPXER9vjL/bt5u9OsaRo1NTVtK1eufPexxx57RtO09ZZlVTMEvNyhogAdkP5h4cI777zz+3fc
+cccF+fn5iSHT3aTufIqt4h/IIxsRVZ8harYDEjQ9Np+5EcIRquV8qVRlzUDln4M96nxU/rfoOJ6t
+JxiGQUVFRevDDz+88aGHHnpeCLHeb+6HzLLoUFOADujAeOC8JUuWLL799tvPnzt3brZpmqhQAhWi
+c0gQNTsQdTsR9bsRjfvh+CHEiUpnJVJIp9tCdOl+x7kAynmLpYFKyYPUsSjPRFTGaajM6ajsGc7t
+HQdF9UiGQNd1tmzZUrNq1aqNq1evfh34CGe7Vtzn9ZFiqCpABzQpZb5t22dMnjz5onvuuWf+VVdd
+VZienq6HlQQrpH97mb+nvnaEtwHajzv7/DqWpqXhpFq7UlHudDBcgVi9bYWVx2AYBg0NDeZrr71W
+8qtf/er90tLSD6WUm23brqCXc/oGG0NdAbrS6QGmAHOuuOKKC2+++eYzFixYMDErK8uwLKvXL2PF
+A1JKNE2jtrbWV1RUtP8vf/nLlrVr134IbAX2AI0MgTG+L5wqCtAVOpAJTAYKZ86cOfcHP/jB7PPO
+O2/cnDlzcj0ej6aUwrKs0MNFpEwSAk3TEELQ2Nhobd269ehHH3108Pnnn99WXFy8BSgBSoE6hqCZ
+77Vvg01AP6EBqUAeMA4Yn5eXV/Dd7363YM6cOaMKCgoyx44d68nNzU3JyMiIaM5YX19vVlVVnTh0
+6FDj3r1767Zu3Xrk73//+97Kysq9OON5Gc4hDMcZwia+L5zqCnAyNCAJSMOxEtn+f9OBtOTk5Izx
+48enZWVlJaWkpCQYhqED+Hw+88SJE221tbUtBw8ebGpubm7AMeENOG91jf/fJqCFU1jgJ+PrpgCh
+oOEkvxg4Q0jH3x2ZKra/WDgm3PT//2sj6GEMYxjDGMYwhjGMYQyjE/8fduTUzhArffwAAAAASUVO
+RK5CYII=
+"
+ id="image3836"
+ x="0"
+ y="0" />
+ <path
+ style="fill:#000000;stroke-width:1.33333337"
+ d=""
+ id="path3838"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+[Desktop Entry]
+Name=Seafile
+Comment=Seafile desktop sync client
+TryExec=seafile-applet
+Exec=seafile-applet
+Icon=seafile
+Type=Application
+Categories=Network;FileTransfer;
--- /dev/null
+Seafile
+-------
+
+For more information about Seafile, please visit http://seafile.com
+
+ -- plt <freeplant@gmail.com> Fri, 30 March 2012 16:43:10 +0800
--- /dev/null
+seafile-gui (7.0.8) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 2 Jun 2020 16:41:28 +0800
+seafile-gui (7.0.7) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Wed, 1 Apr 2020 09:46:00 +0800
+seafile-gui (7.0.6) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 11 Feb 2020 10:18:46 +0800
+seafile-gui (7.0.5) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Sat, 11 Jan 2020 10:46:00 +0800
+seafile-gui (7.0.4) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 19 Nov 2019 11:53:00 +0800
+seafile-gui (7.0.3) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 7 Oct 2019 15:31:10 +0800
+seafile-gui (7.0.2) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Wed, 7 Aug 2019 10:52:10 +0800
+seafile-gui (7.0.1) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 9 Jul 2019 18:25:10 +0800
+seafile-gui (7.0.0) unstable; urgency=low
+
+ * new upstream release
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 28 May 2019 10:20:10 +0800
+seafile-gui (6.2.11) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Thur, 17 Jan 2019 15:53:10 +0800
+seafile-gui (6.2.10) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 15 Jan 2019 16:24:10 +0800
+seafile-gui (6.2.9) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Sat, 8 Dec 2018 11:17:10 +0800
+seafile-gui (6.2.8) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 4 Dec 2018 11:51:10 +0800
+seafile-gui (6.2.7) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 20 Nov 2018 15:56:10 +0800
+seafile-gui (6.2.5) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 11 Sep 2018 16:46:10 +0800
+seafile-gui (6.2.4) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 3 Aug 2018 13:21:10 +0800
+seafile-gui (6.2.3) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 27 Jul 2018 14:40:10 +0800
+seafile-gui (6.2.2) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 6 Jul 2018 17:04:10 +0800
+seafile-gui (6.2.1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 6 Jul 2018 17:04:10 +0800
+seafile-gui (6.2.0) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 26 June 2018 17:04:10 +0800
+seafile-gui (6.1.8) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 8 May 2018 17:04:10 +0800
+seafile-gui (6.1.7) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Thur, 29 Mar 2018 14:48:10 +0800
+seafile-gui (6.1.6) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 2 Mar 2018 12:20:10 +0800
+seafile-gui (6.1.5) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 2 Feb 2018 13:59:10 +0800
+seafile-gui (6.1.4) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 19 Dec 2017 17:01:10 +0800
+seafile-gui (6.1.3) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 3 Nov 2017 13:51:10 +0800
+seafile-gui (6.1.2) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Wed, 25 Oct 2017 13:51:10 +0800
+
+
+seafile-gui (6.1.1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 19 Sep 2017 18:16:10 +0800
+
+seafile-gui (6.1.0) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Wed, 2 Aug 2017 16:37:10 +0800
+seafile-gui (6.0.7) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 20 Jun 2017 16:37:10 +0800
+seafile-gui (6.0.6) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 28 Apr 2017 16:37:10 +0800
+
+seafile-gui (6.0.4) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Tue, 21 Feb 2017 16:17:30 +0800
+
+seafile-gui (6.0.3) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 10 Feb 2017 16:49:07 +0800
+
+seafile-gui (6.0.1) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Mon, 12 Dec 2016 14:51:07 +0800
+
+seafile-gui (6.0.0) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 14 Oct 2016 13:49:07 +0800
+
+seafile-gui (5.1.4) unstable; urgency=low
+
+ * new upstream release
+
+ -- Jonathan Xu <jonathan.xu@seafile.com> Fri, 29 Jul 2016 14:06:38 +0800
+
+seafile-gui (5.1.3-1ubuntu1) UNRELEASED; urgency=medium
+
+ * new upstream release
+
+ -- m.eik michalke <meik.michalke@hhu.de> Fri, 01 Jul 2016 00:04:38 +0200
+
+seafile-gui (5.1.2-5ubuntu2) unstable; urgency=medium
+
+ * fixed package dependencies
+
+ -- m.eik michalke <meik.michalke@hhu.de> Sat, 18 Jun 2016 12:20:04 +0200
+
+seafile-gui (5.1.2-5ubuntu1) unstable; urgency=medium
+
+ * repackaging with cleaned up orig.tar.xz archives
+ * improved the debian/control file
+
+ -- m.eik michalke <meik.michalke@hhu.de> Fri, 17 Jun 2016 19:22:13 +0200
+
+seafile-gui (5.1.2-4) unstable; urgency=medium
+
+ * adjusted build dependencies
+ * updated the debian/copyright notice so people know who's responisble for the packaging
+ * rewrote the rules file, much simpler now
+ * prep for release on github
+
+ -- m.eik michalke <meik.michalke@hhu.de> Thu, 16 Jun 2016 01:06:50 +0200
--- /dev/null
+Source: seafile-gui
+Section: net
+Priority: extra
+Maintainer: m.eik michalke <meik.michalke@hhu.de>
+Build-Depends:
+ debhelper (>= 7),
+ libssl-dev,
+ libcurl4-openssl-dev,
+ libsqlite3-dev,
+ intltool,
+ libglib2.0-dev,
+ libevent-dev,
+ uuid-dev,
+ qtbase5-dev,
+ libqt5webkit5-dev,
+ qttools5-dev,
+ libtool,
+ valac,
+ libjansson-dev,
+ cmake,
+ qtchooser,
+ qttools5-dev-tools,
+ libsearpc-dev (>= 3.1.0),
+ libseafile-dev
+Standards-Version: 3.9.5
+Homepage: http://seafile.com
+
+Package: seafile-gui
+Architecture: any
+Depends:
+ ${shlibs:Depends},
+ ${misc:Depends},
+ seafile-daemon (>= 5.1.2)
+Conflicts: seafile
+Description: Seafile desktop client.
+ Seafile is an open source cloud storage system with features
+ on privacy protection and teamwork. Collections of files are
+ called libraries, and each library can be synced separately.
+ A library can also be encrypted with a user chosen password.
+ Seafile also allows users to create groups and easily sharing
+ files into groups.
+
+Package: seafile-gui-dbg
+Section: debug
+Architecture: any
+Depends:
+ seafile-gui (= ${binary:Version}),
+ ${misc:Depends},
+Description: Debugging symbols for the seafile-gui package.
+ This package contains the debugging symbols for the seafile-gui package.
--- /dev/null
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: seafile-client
+Upstream-Contact: Lingtao Pan <freeplant@gmail.com>
+Source: https://github.com/haiwen/seafile-client
+
+Files: *
+Copyright: 2012 plt
+License: Apache
+ You should have received a copy of the license with your Debian system,
+ in the file /usr/share/common-licenses/Apache-2.0, or with the
+ source package as the file COPYING or LICENSE.
+
+Files: debian/*
+Copyright: 2016 m.eik michalke
+License: GPL-2
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ .
+ This software is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE.
+ .
+ You should have received a copy of the license with your Debian system,
+ in the file /usr/share/common-licenses/GPL-2, or with the
+ source package as the file COPYING or LICENSE.
--- /dev/null
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+%:
+ dh $@ --builddirectory=build
+
+override_dh_auto_configure:
+ export QT_SELECT=5
+ dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release -DBUILD_SHIBBOLETH_SUPPORT=ON
+
+override_dh_auto_build:
+ dh_auto_build --parallel
+
+override_dh_strip:
+ dh_strip -pseafile-gui --dbg-package=seafile-gui-dbg
--- /dev/null
+usr/bin/seafile-applet
+usr/share/pixmaps/seafile.png
+usr/share/applications/seafile.desktop
+usr/share/icons/hicolor/*/apps/seafile.png
--- /dev/null
+3.0 (quilt)
--- /dev/null
+## C++ Coding Style
+
+Refer to `coding-style.md`
+
+## I18N
+
+### update the .ts files
+
+ make update-ts
+
+
+### Add a new language
+
+1. add the language to the LANGUAGES variable in `CMakeLists.txt`
+
+ SET(LANGUAGES zh_CN xx_YY)
+
+2. make update-ts
+
+3. add a line to `seafile-client.qrc`
+
+ <file>i18n/seafile_xx_YY.qm</file>
+
+### Add a New Language Contributed by Others
+
+1. add the language to the LANGUAGES variable in `CMakeLists.txt`
+
+ SET(LANGUAGES zh_CN xx_YY)
+
+2. add a line to `seafile-client.qrc`
+
+ <file>i18n/seafile_xx_YY.qm</file>
+
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(seafile_shell_ext)
+
+OPTION(X32 "Build 32 bit instead of 64bit dll" OFF)
+
+IF (X32)
+ SET(WINVER 0x0501)
+ SET(DLL_NAME seafile_shell_ext)
+ set(CMAKE_RC_COMPILER windres)
+ELSE(X32)
+ SET(WINVER 0x0502)
+ SET(DLL_NAME seafile_shell_ext64)
+ set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
+ENDIF()
+
+IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+ SET(CMAKE_BUILD_TYPE Debug)
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g")
+ENDIF()
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fno-omit-frame-pointer -Wall -Wextra -Wno-unused-parameter -std=c++0x")
+
+ADD_DEFINITIONS(-D_WIN32_WINNT=${WINVER} -DWINVER=${WINVER})
+
+SET(CMAKE_CXX_CREATE_SHARED_LIBRARY
+ "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> -o <TARGET> ${CMAKE_GNULD_IMAGE_VERSION} <OBJECTS> <LINK_LIBRARIES>")
+
+SET(ext_sources
+ dll.cpp
+ shell-ext.cpp
+ class-factory.cpp
+ context-menu.cpp
+ icon-overlay.cpp
+ log.cpp
+ applet-connection.cpp
+ commands.cpp
+ ext-utils.cpp
+ i18n.cpp
+ seafile_shell_ext.def
+ seafile_shell_ext.rc
+)
+
+SET_SOURCE_FILES_PROPERTIES(context-menu.cpp PROPERTIES COMPILE_FLAGS -fpermissive)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+LINK_LIBRARIES(uuid oleaut32 ole32 ws2_32 shlwapi userenv)
+
+ADD_LIBRARY(seafile_shell_ext SHARED ${ext_sources})
+SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
+
+SET_TARGET_PROPERTIES(seafile_shell_ext PROPERTIES
+ LINK_FLAGS "-static -lstdc++ -Wl,--enable-stdcall-fixup"
+ OUTPUT_NAME "${DLL_NAME}"
+ PREFIX "")
--- /dev/null
+This folder contains the code for Seafile Shell extension.
+
+
+## Build 64 bit DLL
+
+Download [MinGW64 toochain](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds/mingw-w64-bin_i686-mingw_20111220.zip/download)
+
+Or download the [online-installer](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win32/Personal%20Builds/mingw-builds/installer/mingw-w64-install.exe/download)
+
+## String Encoding
+
+There are three encoding involved in the extension:
+
+- windows unicode (`wchar_t *`)
+- utf8
+- windows multi bytes encoding (ANSI)
+
+The conventions are:
+
+- Strings in internal data structures must be stored as utf8.
+- Messages exchanged between shell extension and seafile applet should be encoded in utf8.
+
+
+## Debugging tips
+
+When developing the shell extensions, one need to restart the explorer frequently to reload the extension. Here is a piece of code that can programmatically stop explorer: (From http://stackoverflow.com/a/5705965/1467959)
+
+```c
+BOOL ExitExplorer()
+{
+ HWND hWndTray = FindWindow(_T("Shell_TrayWnd"), NULL);
+ return PostMessage(hWndTray, 0x5B4, 0, 0);
+}
+```
--- /dev/null
+#+ -*- mode: org; fill-column: 70; -*-
+#+title: Shell Extension for Seafile using COM
+#+startup: showall
+
+
+* Useful Links
+
+ Introduction to COM - What It Is and How to Use It.
+
+ http://www.codeproject.com/KB/COM/comintro.aspx
+
+ Creating shell extension handlers
+
+ http://msdn.microsoft.com/en-us/library/bb776797.aspx
+
+ Creating context menu handlers
+
+ http://msdn.microsoft.com/en-us/library/bb776881.aspx
+
+
+* What is Shell
+
+ Windows Shell is just the Windows Explorer, i.e. *explorer.exe*.
+
+* What is COM
+
+ + COM is short for "Component Object Model"
+ + COM is always in the form of a DLL with several specific rules.
+ + A DLL is called a *COM Server*, while the one using the dll is
+ called a *COM client*.
+
+ In shell extension, we are writing a COM Server, and the Windows
+ Shell is our client. For example, for a menu handler, which is used
+ to add a customized menu item, the Winodws Explorer calls some
+ function in our COM with a param descrbing the current file for whom
+ the menu is being displayed. In our COM implementation, we decide
+ what menu items to add by analysing this param, and use shell API
+ like =InsertMenuItem= to add menu items.
+
+* How to implement a COM
+
+ COM can be implented in any programming language which has a concept
+ of *function pointer*. In practice, people mainly use C++.
+
+* How do Shell know which function in the interface to call
+
+ Our menu items are to be added in two steps:
+
+ 1) Shell queries you where is the handler function, and you give a
+ pointer to it;
+ 2) Shell calls this function using that pointer and corresponding
+ args.
+
+
+ To be concrete, you provide a =QueryInterface()= function, and
+ accept a GUID as one of the params. In the implementation of this
+ function, if the guid param is =IID_IContextMenu=, you just return
+ the func pointer to the context menu hanlder, and the shell will use
+ that pointer to call your menu hanlder, which is your main routine
+ to add your customized menu items, later on.
+
+
+* Control flow of the display a customized menu
+
+ 1) users right click
+
+ 2) shell finds the registration info in system registry and gets to
+ know we are intereseted to add customized menu items
+
+ 3) shell loads the dll, and calls Dll's GetClassObject function,
+ which return a pointer to dll's *factory class*.
+
+ 4) shell calls factory's CreateInstance method to create a object of
+ the extension, i.e. seaf_shell_ext.
+
+ 5) shell calls seaf_shell_ext->vtable->initialize with args to tell
+ the extension about the calling enviroment: whether the click is
+ a background click, or a click on a file; and supply the file
+ object or a folder object as well.
+
+ 6) shell asks the extension object for the IContextMenu Interface,
+ i.e. calls its QueryInterface method with IID_IContextMenu as a
+ param. The object returns a pointer to the seaf_menu structure.
+
+ 7) shell calls the seaf_menu->vtable->QueryContextMenu, and we
+ decide *what to add to the menu.*
+
+
--- /dev/null
+#define __STDC_LIMIT_MACROS
+#include "ext-common.h"
+
+#include <memory>
+
+#include "ext-utils.h"
+#include "log.h"
+
+#include "applet-connection.h"
+
+namespace {
+
+const char *kSeafExtPipeName = "\\\\.\\pipe\\seafile_ext_pipe";
+
+struct ThreadData {
+ seafile::AppletConnection *conn;
+ std::string cmd;
+};
+
+DWORD WINAPI sendDataWrapper (void *vdata)
+{
+ ThreadData *tdata = (ThreadData *)vdata;
+ bool ret = tdata->conn->sendCommandAndWait(tdata->cmd, NULL);
+ delete tdata;
+ ExitThread(ret);
+ return 0;
+}
+
+} // namespace
+
+namespace seafile {
+
+AppletConnection::AppletConnection()
+ : connected_(false),
+ pipe_(INVALID_HANDLE_VALUE),
+ last_conn_failure_(0)
+{
+}
+
+AppletConnection *AppletConnection::singleton_;
+
+AppletConnection *AppletConnection::instance()
+{
+ if (!singleton_) {
+ static AppletConnection v;
+ singleton_ = &v;
+ }
+ return singleton_;
+}
+
+
+bool
+AppletConnection::connect ()
+{
+ if (pipe_ != INVALID_HANDLE_VALUE) {
+ CloseHandle (pipe_);
+ }
+ pipe_ = CreateFile(
+ kSeafExtPipeName, // pipe name
+ GENERIC_READ | // read and write access
+ GENERIC_WRITE,
+ 0, // no sharing
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing pipe
+ FILE_FLAG_OVERLAPPED, // default attributes
+ NULL); // no template file
+
+ if (pipe_ == INVALID_HANDLE_VALUE) {
+ if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+ seaf_ext_log("Failed to create named pipe: %s", utils::formatErrorMessage().c_str());
+ }
+ connected_ = false;
+ last_conn_failure_ = utils::currentMSecsSinceEpoch();
+ return false;
+ }
+
+ DWORD mode = PIPE_READMODE_MESSAGE;
+ if (!SetNamedPipeHandleState(pipe_, &mode, NULL, NULL)) {
+ seaf_ext_log("Failed to set named pipe mode: %s", utils::formatErrorMessage().c_str());
+ onPipeError();
+ last_conn_failure_ = utils::currentMSecsSinceEpoch();
+ return false;
+ }
+
+ connected_ = true;
+ return true;
+}
+
+bool
+AppletConnection::prepare()
+{
+ // HANDLE h_ev = CreateEvent
+ // (NULL, /* security attribute */
+ // FALSE, /* manual reset */
+ // FALSE, /* initial state */
+ // NULL); /* event name */
+
+ // if (!h_ev) {
+ // return false;
+ // }
+ return true;
+}
+
+
+bool AppletConnection::sendCommand(const std::string& cmd)
+{
+ ThreadData *tdata = new ThreadData;
+ tdata->conn = this;
+ tdata->cmd = cmd;
+ utils::doInThread((LPTHREAD_START_ROUTINE)sendDataWrapper, (void *)tdata);
+ return true;
+}
+
+bool AppletConnection::sendCommandAndWait(const std::string& cmd, std::string *resp)
+{
+ utils::MutexLocker lock(&mutex_);
+ if (!sendWithReconnect(cmd)) {
+ return false;
+ }
+
+ std::string r;
+ if (!readResponse(&r)) {
+ return false;
+ }
+
+ if (resp != NULL) {
+ *resp = r;
+ }
+
+ return true;
+}
+
+void AppletConnection::onPipeError()
+{
+ CloseHandle(pipe_);
+ pipe_ = INVALID_HANDLE_VALUE;
+ connected_ = false;
+}
+
+bool AppletConnection::writeRequest(const std::string& cmd)
+{
+ uint32_t len = cmd.size();
+ if (!utils::pipeWriteN(pipe_, &len, sizeof(len))) {
+ onPipeError();
+ seaf_ext_log("failed to send command: %s", utils::formatErrorMessage().c_str());
+ return false;
+ }
+
+ if (!utils::pipeWriteN(pipe_, cmd.c_str(), len)) {
+ onPipeError();
+ seaf_ext_log("failed to send command: %s", utils::formatErrorMessage().c_str());
+ return false;
+ }
+ return true;
+}
+
+bool AppletConnection::readResponse(std::string *out)
+{
+ uint32_t len = 0;
+ if (!utils::pipeReadN(pipe_, &len, sizeof(len))) {
+ onPipeError();
+ return false;
+ }
+
+ // avoid integer overflow
+ if (len == UINT32_MAX) {
+ return false;
+ }
+
+ if (len == 0) {
+ return true;
+ }
+
+ std::unique_ptr<char[]> buf(new char[len + 1]);
+ buf.get()[len] = 0;
+ if (!utils::pipeReadN(pipe_, buf.get(), len)) {
+ onPipeError();
+ return false;
+ }
+
+ if (out != NULL) {
+ *out = buf.get();
+ }
+
+ return true;
+}
+
+bool AppletConnection::sendWithReconnect(const std::string& cmd)
+{
+ uint64_t now = utils::currentMSecsSinceEpoch();
+ if (!connected_ && now - last_conn_failure_ < 2000) {
+ return false;
+ }
+ if (!connected_) {
+ if (connect() && writeRequest(cmd)) {
+ return true;
+ }
+ } else {
+ if (writeRequest(cmd)) {
+ return true;
+ } else if (!connected_ && connect()) {
+ // Retry one more time when connection is broken. This normally
+ // happens when seafile client was restarted.
+ seaf_ext_log ("reconnected to seafile cient");
+ if (writeRequest(cmd)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+} // namespace seafile
--- /dev/null
+#ifndef SEAFILE_EXTENSION_APPLET_CONNECTION_H
+#define SEAFILE_EXTENSION_APPLET_CONNECTION_H
+
+#include <string>
+#include "ext-utils.h"
+
+namespace seafile {
+
+/**
+ * Connection to the seafile appplet, thourgh which the shell extension would
+ * execute an `AppletCommand`.
+ *
+ * It connects to seafile appelt through a named pipe.
+ */
+class AppletConnection {
+public:
+ static AppletConnection *instance();
+
+ bool prepare();
+ bool connect();
+
+ /**
+ * Send the command in a separate thread, returns immediately
+ */
+ bool sendCommand(const std::string& data);
+
+ /**
+ * Send the command and blocking wait for response.
+ */
+ bool sendCommandAndWait(const std::string& data, std::string *resp);
+
+private:
+ AppletConnection();
+ bool readResponse(std::string *out);
+ bool writeRequest(const std::string& cmd);
+ void onPipeError();
+
+ /**
+ * When sending request to seafile client, we would retry one
+ * more time if we're sure the connection to seafile client is broken.
+ * This normally happens when seafile client was restarted.
+ */
+ bool sendWithReconnect(const std::string& cmd);
+
+ static AppletConnection *singleton_;
+
+ bool connected_;
+ HANDLE pipe_;
+
+ uint64_t last_conn_failure_;
+
+ /**
+ * We have only one connection for each explorer process, so when sending
+ * a command to seafile client we need to ensure exclusive access.
+ */
+ utils::Mutex mutex_;
+};
+
+} // namespace seafile
+
+#endif // SEAFILE_EXTENSION_APPLET_CONNECTION_H
--- /dev/null
+#!/bin/bash
+
+set -e
+
+unset -v CPPFLAGS CFLAGS CXXFLAGS LDFLAGS
+
+SCRIPT=$(readlink -f "$0")
+SRCDIR=$(dirname "${SCRIPT}")
+
+cd $SRCDIR
+
+rm -rf CMakeCache.txt CMakeFiles
+export CXX=g++
+cmake -DX32=ON -G "MSYS Makefiles" .
+make
+
+rm -rf CMakeCache.txt CMakeFiles
+export CXX=x86_64-w64-mingw32-g++
+cmake -G "MSYS Makefiles" .
+make
--- /dev/null
+
+#include "ext-common.h"
+
+#include "class-factory.h"
+#include "shell-ext.h"
+#include "log.h"
+
+ShellExtClassFactory::ShellExtClassFactory(seafile::RepoInfo::Status status)
+{
+ m_cRef = 0L;
+ status_ = status;
+
+ // seaf_ext_log ("new ShellExtClassFactory created for status %d\n", int(status));
+
+ InterlockedIncrement(&g_cRefThisDll);
+}
+
+ShellExtClassFactory::~ShellExtClassFactory()
+{
+ InterlockedDecrement(&g_cRefThisDll);
+}
+
+STDMETHODIMP ShellExtClassFactory::QueryInterface(REFIID riid,
+ LPVOID FAR *ppv)
+{
+ if (ppv == 0)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ // Any interface on this object is the object pointer
+
+ if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory))
+ {
+ *ppv = static_cast<LPCLASSFACTORY>(this);
+ AddRef();
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+STDMETHODIMP_(ULONG) ShellExtClassFactory::AddRef()
+{
+ return ++m_cRef;
+}
+
+STDMETHODIMP_(ULONG) ShellExtClassFactory::Release()
+{
+ if (--m_cRef)
+ return m_cRef;
+
+ delete this;
+
+ return 0L;
+}
+
+STDMETHODIMP ShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ if(ppvObj == 0)
+ return E_POINTER;
+
+ *ppvObj = NULL;
+
+ // Shell extensions typically don't support aggregation (inheritance)
+
+ if (pUnkOuter)
+ return CLASS_E_NOAGGREGATION;
+
+ // Create the main shell extension object. The shell will then call
+ // QueryInterface with IID_IShellExtInit--this is how shell extensions are
+ // initialized.
+
+ ShellExt* pShellExt = new ShellExt(status_); // Create the ShellExt object
+
+ const HRESULT hr = pShellExt->QueryInterface(riid, ppvObj);
+ if(FAILED(hr))
+ delete pShellExt;
+ return hr;
+}
+
+STDMETHODIMP ShellExtClassFactory::LockServer(BOOL /*fLock*/)
+{
+ return E_NOTIMPL;
+}
--- /dev/null
+#ifndef SEAFILE_EXT_SHELL_EXT_CLASS_FACTORY_H
+#define SEAFILE_EXT_SHELL_EXT_CLASS_FACTORY_H
+
+#include "shell-ext.h"
+
+/**
+ * Class factory's main responsibility is implemented in its `CreateInstance`
+ * member function, which creates instances of the required shell extension
+ * interface, such as IContextMenu.
+ *
+ * Class factory object is created by `DllGetClassObject` method for this
+ * extension.
+ */
+class ShellExtClassFactory : public IClassFactory
+{
+protected:
+ ULONG m_cRef;
+
+ seafile::RepoInfo::Status status_;
+
+public:
+ ShellExtClassFactory(seafile::RepoInfo::Status status = seafile::RepoInfo::NoStatus);
+ virtual ~ShellExtClassFactory();
+
+ //@{
+ /// IUnknown members
+ STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+ //@}
+
+ //@{
+ /// IClassFactory members
+ STDMETHODIMP CreateInstance(LPUNKNOWN, REFIID, LPVOID FAR *);
+ STDMETHODIMP LockServer(BOOL);
+ //@}
+};
+
+#endif // SEAFILE_EXT_SHELL_EXT_CLASS_FACTORY_H
--- /dev/null
+#include "ext-common.h"
+
+#include "log.h"
+#include "applet-connection.h"
+#include "ext-utils.h"
+
+#include "commands.h"
+
+namespace seafile {
+
+uint64_t reposInfoTimestamp = 0;
+
+std::string toString(RepoInfo::Status st) {
+ switch (st) {
+ case RepoInfo::NoStatus:
+ return "nostatus";
+ case RepoInfo::Paused:
+ return "paused";
+ case RepoInfo::Normal:
+ return "synced";
+ case RepoInfo::Syncing:
+ return "syncing";
+ case RepoInfo::Error:
+ return "error";
+ case RepoInfo::ReadOnly:
+ return "readonly";
+ case RepoInfo::LockedByMe:
+ return "locked by me";
+ case RepoInfo::LockedByOthers:
+ return "locked by someone else";
+ case RepoInfo::N_Status:
+ return "";
+ }
+ return "";
+}
+
+
+GetShareLinkCommand::GetShareLinkCommand(const std::string path)
+ : AppletCommand<void>("get-share-link"),
+ path_(path)
+{
+}
+
+std::string GetShareLinkCommand::serialize()
+{
+ return path_;
+}
+
+GetInternalLinkCommand::GetInternalLinkCommand(const std::string path)
+ : AppletCommand<void>("get-internal-link"),
+ path_(path)
+{
+}
+
+std::string GetInternalLinkCommand::serialize()
+{
+ return path_;
+}
+
+ListReposCommand::ListReposCommand()
+ : AppletCommand<RepoInfoList>("list-repos")
+{
+}
+
+std::string ListReposCommand::serialize()
+{
+ char buf[512];
+ snprintf (buf, sizeof(buf), "%I64u", reposInfoTimestamp);
+ return buf;
+}
+
+bool ListReposCommand::parseResponse(const std::string& raw_resp,
+ RepoInfoList* infos)
+{
+ std::vector<std::string> lines = utils::split(raw_resp, '\n');
+ if (lines.empty()) {
+ return true;
+ }
+ for (size_t i = 0; i < lines.size(); i++) {
+ std::string line = lines[i];
+ std::vector<std::string> parts = utils::split(line, '\t');
+ if (parts.size() != 6) {
+ continue;
+ }
+ std::string repo_id, repo_name, worktree, status;
+ RepoInfo::Status st;
+ bool support_file_lock;
+ bool support_private_share;
+
+ repo_id = parts[0];
+ repo_name = parts[1];
+ worktree = utils::normalizedPath(parts[2]);
+ status = parts[3];
+ support_file_lock = parts[4] == "file-lock-supported";
+ support_private_share = parts[5] == "private-share-supported";
+ if (status == "paused") {
+ st = RepoInfo::Paused;
+ }
+ else if (status == "syncing") {
+ st = RepoInfo::Syncing;
+ }
+ else if (status == "error") {
+ st = RepoInfo::Error;
+ }
+ else if (status == "normal") {
+ st = RepoInfo::Normal;
+ }
+ else {
+ // impossible
+ seaf_ext_log("bad repo status \"%s\"", status.c_str());
+ continue;
+ }
+ // seaf_ext_log ("status for %s is \"%s\"", repo_name.c_str(),
+ // status.c_str());
+ infos->push_back(RepoInfo(repo_id, repo_name, worktree, st,
+ support_file_lock, support_private_share));
+ }
+
+ reposInfoTimestamp = utils::currentMSecsSinceEpoch();
+ return true;
+}
+
+GetFileStatusCommand::GetFileStatusCommand(const std::string& repo_id,
+ const std::string& path_in_repo,
+ bool isdir)
+ : AppletCommand<RepoInfo::Status>("get-file-status"),
+ repo_id_(repo_id),
+ path_in_repo_(path_in_repo),
+ isdir_(isdir)
+{
+}
+
+std::string GetFileStatusCommand::serialize()
+{
+ char buf[512];
+ snprintf (buf, sizeof(buf), "%s\t%s\t%s",
+ repo_id_.c_str(), path_in_repo_.c_str(), isdir_ ? "true" : "false");
+ return buf;
+}
+
+bool GetFileStatusCommand::parseResponse(const std::string& raw_resp,
+ RepoInfo::Status *status)
+{
+ // seaf_ext_log ("raw_resp is %s\n", raw_resp.c_str());
+
+ if (raw_resp == "syncing") {
+ *status = RepoInfo::Syncing;
+ } else if (raw_resp == "synced") {
+ *status = RepoInfo::Normal;
+ } else if (raw_resp == "error") {
+ *status = RepoInfo::Error;
+ } else if (raw_resp == "paused") {
+ *status = RepoInfo::Paused;
+ } else if (raw_resp == "readonly") {
+ *status = RepoInfo::ReadOnly;
+ } else if (raw_resp == "locked") {
+ *status = RepoInfo::LockedByOthers;
+ } else if (raw_resp == "locked_by_me") {
+ *status = RepoInfo::LockedByMe;
+ } else if (raw_resp == "ignored") {
+ *status = RepoInfo::NoStatus;
+ } else {
+ *status = RepoInfo::NoStatus;
+
+ // seaf_ext_log ("[GetFileStatusCommand] status for %s is %s, raw_resp is %s\n",
+ // path_in_repo_.c_str(),
+ // seafile::toString(*status).c_str(), raw_resp.c_str());
+ }
+
+ return true;
+}
+
+LockFileCommand::LockFileCommand(const std::string& path)
+ : AppletCommand<void>("lock-file"),
+ path_(path)
+{
+}
+
+std::string LockFileCommand::serialize()
+{
+ return path_;
+}
+
+UnlockFileCommand::UnlockFileCommand(const std::string& path)
+ : AppletCommand<void>("unlock-file"),
+ path_(path)
+{
+}
+
+std::string UnlockFileCommand::serialize()
+{
+ return path_;
+}
+
+PrivateShareCommand::PrivateShareCommand(const std::string& path, bool to_group)
+ : AppletCommand<void>(to_group ? "private-share-to-group"
+ : "private-share-to-user"),
+ path_(path)
+{
+}
+
+std::string PrivateShareCommand::serialize()
+{
+ return path_;
+}
+
+ShowHistoryCommand::ShowHistoryCommand(const std::string& path)
+ : AppletCommand<void>("show-history"),
+ path_(path)
+{
+}
+
+std::string ShowHistoryCommand::serialize()
+{
+ return path_;
+}
+
+} // namespace seafile
--- /dev/null
+#ifndef SEAFILE_EXTENSION_APPLET_COMMANDS_H
+#define SEAFILE_EXTENSION_APPLET_COMMANDS_H
+
+#include <string>
+#include <vector>
+
+#include "applet-connection.h"
+
+namespace seafile {
+class RepoInfo
+{
+public:
+ enum Status {
+ NoStatus = 0,
+ Paused,
+ Normal,
+ Syncing,
+ Error,
+ LockedByMe,
+ LockedByOthers,
+ ReadOnly,
+ N_Status,
+ };
+
+ std::string repo_id;
+ std::string repo_name;
+ std::string worktree;
+ Status status;
+ bool support_file_lock;
+ bool support_private_share;
+
+ RepoInfo() : status(NoStatus)
+ {
+ }
+
+ RepoInfo(const std::string& repo_id,
+ const std::string repo_name,
+ const std::string& worktree,
+ Status status,
+ bool support_file_lock,
+ bool support_private_share)
+ : repo_id(repo_id),
+ repo_name(repo_name),
+ worktree(worktree),
+ status(status),
+ support_file_lock(support_file_lock),
+ support_private_share(support_private_share)
+ {
+ }
+
+ bool isValid()
+ {
+ return !repo_id.empty();
+ }
+};
+
+std::string toString(RepoInfo::Status st);
+
+typedef std::vector<RepoInfo> RepoInfoList;
+
+/**
+ * Abstract base class for all commands sent to seafile applet.
+ */
+template<class T>
+class AppletCommand {
+public:
+ AppletCommand(std::string name) : name_(name) {}
+
+ /**
+ * send the command to seafile client, don't need the response
+ */
+ void send()
+ {
+ AppletConnection::instance()->sendCommand(formatRequest());
+ }
+
+ std::string formatRequest()
+ {
+ return name_ + "\t" + serialize();
+ }
+
+ /**
+ * send the command to seafile client, and wait for the response
+ */
+ bool sendAndWait(T *resp)
+ {
+ std::string raw_resp;
+ if (!AppletConnection::instance()->sendCommandAndWait(formatRequest(), &raw_resp)) {
+ return false;
+ }
+
+ return parseResponse(raw_resp, resp);
+ }
+
+protected:
+ /**
+ * Prepare this command for sending through the pipe
+ */
+ virtual std::string serialize() = 0;
+
+ /**
+ * Parse response from seafile applet. Commands that don't need the
+ * respnse can inherit the implementation of the base class, which does
+ * nothing.
+ */
+ virtual bool parseResponse(const std::string& raw_resp, T *resp)
+ {
+ return true;
+ }
+
+private:
+ std::string name_;
+};
+
+
+class GetShareLinkCommand : public AppletCommand<void> {
+public:
+ GetShareLinkCommand(const std::string path);
+
+protected:
+ std::string serialize();
+
+private:
+ std::string path_;
+};
+
+class GetInternalLinkCommand : public AppletCommand<void> {
+public:
+ GetInternalLinkCommand(const std::string path);
+
+protected:
+ std::string serialize();
+
+private:
+ std::string path_;
+};
+
+
+class ListReposCommand : public AppletCommand<RepoInfoList> {
+public:
+ ListReposCommand();
+
+protected:
+ std::string serialize();
+
+ bool parseResponse(const std::string& raw_resp, RepoInfoList *worktrees);
+};
+
+class GetFileStatusCommand : public AppletCommand<RepoInfo::Status> {
+public:
+ GetFileStatusCommand(const std::string& repo_id, const std::string& path_in_repo, bool isdir);
+
+protected:
+ std::string serialize();
+
+ bool parseResponse(const std::string& raw_resp, RepoInfo::Status *status);
+
+private:
+ std::string repo_id_;
+ std::string path_in_repo_;
+ bool isdir_;
+};
+
+class LockFileCommand : public AppletCommand<void> {
+public:
+ LockFileCommand(const std::string& path);
+
+protected:
+ std::string serialize();
+
+private:
+ std::string path_;
+};
+
+class UnlockFileCommand : public AppletCommand<void> {
+public:
+ UnlockFileCommand(const std::string& path);
+
+protected:
+ std::string serialize();
+
+private:
+ std::string path_;
+};
+
+class PrivateShareCommand : public AppletCommand<void> {
+public:
+ PrivateShareCommand(const std::string& path, bool to_group);
+
+protected:
+ std::string serialize();
+
+private:
+ std::string path_;
+ bool to_group;
+};
+
+class ShowHistoryCommand : public AppletCommand<void> {
+public:
+ ShowHistoryCommand(const std::string& path);
+
+protected:
+ std::string serialize();
+
+private:
+ std::string path_;
+};
+
+}
+
+#endif // SEAFILE_EXTENSION_APPLET_COMMANDS_H
--- /dev/null
+#include "ext-common.h"
+#include "ext-utils.h"
+#include "shell-ext.h"
+#include "log.h"
+#include "commands.h"
+#include "i18n.h"
+
+#define SEAFILE_TR(x) seafile::getString((x)).c_str()
+
+namespace utils = seafile::utils;
+
+namespace {
+
+bool shouldIgnorePath(const std::string& path)
+{
+ /* Show no menu for drive root, such as C: D: */
+ if (path.size() <= 3) {
+ return TRUE;
+ }
+
+ /* Ignore flash disk, network mounted drive, etc. */
+ if (GetDriveType(path.substr(0, 3).c_str()) != DRIVE_FIXED) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+const char *kMainMenuName = "Seafile";
+
+}
+
+
+STDMETHODIMP ShellExt::Initialize(LPCITEMIDLIST pIDFolder,
+ LPDATAOBJECT pDataObj,
+ HKEY hRegKey)
+{
+ return Initialize_Wrap(pIDFolder, pDataObj, hRegKey);
+}
+
+STDMETHODIMP ShellExt::Initialize_Wrap(LPCITEMIDLIST folder,
+ LPDATAOBJECT data,
+ HKEY /* hRegKey */)
+{
+ FORMATETC format = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
+ STGMEDIUM stg = {TYMED_HGLOBAL, {L'\0'}, NULL};
+ HDROP drop;
+ UINT count;
+ UINT size;
+ HRESULT result = S_OK;
+ wchar_t path_dir_w[4096];
+ std::unique_ptr<wchar_t[]> path_w;
+
+ active_menu_items_.clear();
+
+ /* 'folder' param is not null only when clicking at the foler background;
+ When right click on a file, it's NULL */
+ if (folder) {
+ if (SHGetPathFromIDListW(folder, path_dir_w)) {
+ path_ = utils::normalizedPath(utils::wStringToUtf8(path_dir_w));
+ }
+ }
+
+ /* if 'data' is NULL, then it's a background click, we have set
+ * path_ to folder's name above, and the Init work is done */
+ if (!data)
+ return S_OK;
+
+ /* 'data' is no null, which means we are operating on a file. The
+ * following lines until the end of the function is used to extract the
+ * filename of the current file. */
+ if (FAILED(data->GetData(&format, &stg)))
+ return E_INVALIDARG;
+
+ drop = (HDROP)GlobalLock(stg.hGlobal);
+ if (!drop)
+ return E_INVALIDARG;
+
+ // When the function copies a file name to the buffer, the return value is a
+ // count of the characters copied, not including the terminating null
+ // character.
+ count = DragQueryFileW(drop, 0xFFFFFFFF, NULL, 0);
+ if (count == 0) {
+ result = E_INVALIDARG;
+ } else if (count > 1) {
+ result = S_FALSE;
+ } else {
+ size = DragQueryFileW(drop, 0, NULL, 0);
+ if (!size) {
+ result = E_INVALIDARG;
+ } else {
+ path_w.reset(new wchar_t[size+1]);
+ if (!DragQueryFileW(drop, 0, path_w.get(), size+1))
+ result = E_INVALIDARG;
+ }
+ }
+
+ GlobalUnlock(stg.hGlobal);
+ ReleaseStgMedium(&stg);
+
+ if (result == S_OK) {
+ path_ = utils::normalizedPath(utils::wStringToUtf8(path_w.get()));
+ }
+
+ return result;
+}
+
+STDMETHODIMP ShellExt::QueryContextMenu(HMENU hMenu,
+ UINT indexMenu,
+ UINT idCmdFirst,
+ UINT idCmdLast,
+ UINT uFlags)
+{
+ return QueryContextMenu_Wrap(hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
+}
+
+
+STDMETHODIMP ShellExt::QueryContextMenu_Wrap(HMENU menu,
+ UINT indexMenu,
+ UINT first_command,
+ UINT last_command,
+ UINT flags)
+{
+ if (!seafile::utils::isShellExtEnabled()) {
+ return S_OK;
+ }
+ /* do nothing when user is double clicking */
+ if (flags & CMF_DEFAULTONLY)
+ return S_OK;
+
+ if (shouldIgnorePath(path_)) {
+ return S_OK;
+ }
+
+ std::string path_in_repo;
+ seafile::RepoInfo repo;
+ if (!pathInRepo(path_, &path_in_repo, &repo) || path_in_repo.size() <= 1) {
+ return S_OK;
+ }
+
+ next_active_item_ = 0;
+
+ main_menu_ = menu;
+ first_ = first_command;
+ last_ = last_command;
+ index_ = 0;
+
+ buildSubMenu(repo, path_in_repo);
+
+ if (!insertMainMenu()) {
+ return S_FALSE;
+ }
+
+ return MAKE_HRESULT(
+ SEVERITY_SUCCESS, FACILITY_NULL, 3 + next_active_item_);
+}
+
+void ShellExt::tweakMenu(HMENU menu)
+{
+ MENUINFO MenuInfo;
+ MenuInfo.cbSize = sizeof(MenuInfo);
+ MenuInfo.fMask = MIM_STYLE | MIM_APPLYTOSUBMENUS;
+ MenuInfo.dwStyle = MNS_CHECKORBMP;
+
+ SetMenuInfo(menu, &MenuInfo);
+}
+
+STDMETHODIMP ShellExt::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+ return InvokeCommand_Wrap(lpcmi);
+}
+
+// This is called when you invoke a command on the menu
+STDMETHODIMP ShellExt::InvokeCommand_Wrap(LPCMINVOKECOMMANDINFO info)
+{
+ // see http://stackoverflow.com/questions/11443282/winapi-shell-extension-overriding-windows-command
+ if (HIWORD(info->lpVerb))
+ return E_INVALIDARG;
+
+ if (path_.empty()) {
+ return E_INVALIDARG;
+ }
+
+ UINT id = LOWORD(info->lpVerb);
+ if (id == 0)
+ return S_OK;
+
+ id--;
+ if (id > active_menu_items_.size() - 1) {
+ seaf_ext_log ("invalid menu id %u", id);
+ return S_FALSE;
+ }
+
+ MenuOp op = active_menu_items_[id];
+
+ if (op == GetShareLink) {
+ seafile::GetShareLinkCommand cmd(path_);
+ cmd.send();
+ } else if (op == GetInternalLink) {
+ seafile::GetInternalLinkCommand cmd(path_);
+ cmd.send();
+ } else if (op == LockFile) {
+ seafile::LockFileCommand cmd(path_);
+ cmd.send();
+ } else if (op == UnlockFile) {
+ seafile::UnlockFileCommand cmd(path_);
+ cmd.send();
+ } else if (op == ShareToUser) {
+ seafile::PrivateShareCommand cmd(path_, false);
+ cmd.send();
+ } else if (op == ShareToGroup) {
+ seafile::PrivateShareCommand cmd(path_, true);
+ cmd.send();
+ } else if (op == ShowHistory) {
+ seafile::ShowHistoryCommand cmd(path_);
+ cmd.send();
+ }
+
+ return S_OK;
+}
+
+STDMETHODIMP ShellExt::GetCommandString(UINT_PTR idCmd,
+ UINT flags,
+ UINT FAR * reserved,
+ LPSTR pszName,
+ UINT cchMax)
+{
+ return GetCommandString_Wrap(idCmd, flags, reserved, pszName, cchMax);
+}
+
+// This is for the status bar and things like that:
+STDMETHODIMP ShellExt::GetCommandString_Wrap(UINT_PTR idCmd,
+ UINT flags,
+ UINT FAR * /*reserved*/,
+ LPSTR pszName,
+ UINT cchMax)
+{
+ lstrcpynW((LPWSTR)pszName, L"This is Seafile help string.", cchMax);
+ return S_OK;
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return HandleMenuMsg_Wrap(uMsg, wParam, lParam);
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT res;
+ return HandleMenuMsg2(uMsg, wParam, lParam, &res);
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
+{
+ return HandleMenuMsg2_Wrap(uMsg, wParam, lParam, pResult);
+}
+
+STDMETHODIMP ShellExt::HandleMenuMsg2_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult)
+{
+ return S_OK;
+}
+
+/**
+ * Add two menu seperators, with seafile menu between them
+ */
+bool ShellExt::insertMainMenu()
+{
+ // Insert a seperate before seafile menu
+ if (!InsertMenu(main_menu_, index_++, MF_BYPOSITION |MF_SEPARATOR, 0, ""))
+ return FALSE;
+
+ MENUITEMINFO menuiteminfo;
+ ZeroMemory(&menuiteminfo, sizeof(menuiteminfo));
+ menuiteminfo.cbSize = sizeof(menuiteminfo);
+ menuiteminfo.fMask = MIIM_FTYPE | MIIM_SUBMENU | MIIM_STRING | MIIM_ID;
+ menuiteminfo.fType = MFT_STRING;
+ menuiteminfo.dwTypeData = (char*)kMainMenuName;
+ menuiteminfo.cch = strlen(kMainMenuName);
+ // menuiteminfo.hbmpItem = HBMMENU_CALLBACK;
+ menuiteminfo.hSubMenu = sub_menu_;
+ menuiteminfo.wID = first_;
+
+ if (!InsertMenuItem(main_menu_, index_++, TRUE, &menuiteminfo))
+ return FALSE;
+
+ // Insert a seperate after seafile menu
+ if (!InsertMenu(main_menu_, index_++, MF_BYPOSITION |MF_SEPARATOR, 0, ""))
+ return FALSE;
+
+ /* Set menu styles of submenu */
+ tweakMenu(main_menu_);
+
+ return TRUE;
+}
+
+MENUITEMINFO
+ShellExt::createMenuItem(const std::string& text)
+{
+ MENUITEMINFO minfo;
+ memset(&minfo, 0, sizeof(minfo));
+ minfo.cbSize = sizeof(MENUITEMINFO);
+ minfo.fMask = MIIM_FTYPE | MIIM_BITMAP | MIIM_STRING | MIIM_ID;
+ minfo.fType = MFT_STRING;
+ minfo.dwTypeData = (char *)text.c_str();
+ minfo.cch = text.size();
+ minfo.hbmpItem = HBMMENU_CALLBACK;
+ minfo.wID = first_ + 1 + next_active_item_++;
+
+ return minfo;
+}
+
+void ShellExt::insertSubMenuItem(const std::string& text, MenuOp op)
+{
+ MENUITEMINFO minfo;
+ minfo = createMenuItem(text);
+ InsertMenuItem (sub_menu_, /* menu */
+ index_++, /* position */
+ TRUE, /* by position */
+ &minfo);
+ active_menu_items_.push_back(op);
+}
+
+
+void ShellExt::buildSubMenu(const seafile::RepoInfo& repo,
+ const std::string& path_in_repo)
+{
+ insertSubMenuItem(SEAFILE_TR("get seafile download link"), GetShareLink);
+ insertSubMenuItem(SEAFILE_TR("get seafile internal link"), GetInternalLink);
+
+ std::unique_ptr<wchar_t[]> path_w(utils::utf8ToWString(path_));
+ bool is_dir = GetFileAttributesW(path_w.get()) & FILE_ATTRIBUTE_DIRECTORY;
+ if (repo.support_private_share && is_dir) {
+ insertSubMenuItem(SEAFILE_TR("share to a user"), ShareToUser);
+ insertSubMenuItem(SEAFILE_TR("share to a group"), ShareToGroup);
+ }
+
+ if (repo.support_file_lock && !is_dir) {
+ seafile::RepoInfo::Status status =
+ getRepoFileStatus(repo.repo_id, path_in_repo, false);
+
+ if (status == seafile::RepoInfo::LockedByMe) {
+ insertSubMenuItem(SEAFILE_TR("unlock this file"), UnlockFile);
+ }
+ else if (status != seafile::RepoInfo::LockedByOthers) {
+ insertSubMenuItem(SEAFILE_TR("lock this file"), LockFile);
+ }
+ }
+
+ if (!is_dir) {
+ insertSubMenuItem(SEAFILE_TR("view file history"), ShowHistory);
+ }
+}
--- /dev/null
+Windows Registry Editor Version 5.00
+
+# context menu handler
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"="Seafile"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}]
+@="Seafile"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\*\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+[HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers\Seafile]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"
+
+# Icon Overlay 1 (normal repo icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}"="SeafileIconNormal"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}]
+@="SeafileIconNormal"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconNormal"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}"
+
+
+# Icon Overlay 2 (syncing icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}"="SeafileIconSyncing"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}]
+@="SeafileIconSyncing"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconSyncing"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}"
+
+# Icon Overlay 3 (error icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}"="SeafileIconError"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}]
+@="SeafileIconError"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconError"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}"
+
+# Icon Overlay 4 (paused icon)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}"="SeafileIconPaused"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}]
+@="SeafileIconPaused"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconPaused"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}"
+
+# Icon Overlay 5 (locked by me)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}"="SeafileIconLockedByMe"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}]
+@="SeafileIconLockedByMe"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByMe"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}"
+
+# Icon Overlay 6 (locked by others)
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}"="SeafileIconLockedByOthers"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}]
+@="SeafileIconLockedByOthers"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}\InProcServer32]
+@="F:\\dev\\seafile_shell_ext64.dll"
+"ThreadingModel"="Apartment"
+
+[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByOthers"]
+@="{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}"
\ No newline at end of file
--- /dev/null
+Windows Registry Editor Version 5.00
+
+# approved ext
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}"=-
+
+# register shell extension
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Seafile]
+
+# context menu handler
+[-HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\*\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\Seafile]
+
+[-HKEY_CLASSES_ROOT\Folder\shellex\ContextMenuHandlers\Seafile]
+
+# Icon Overlay IconNormal
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE607}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconNormal"]
+
+# Icon Overlay IconSyncing
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE608}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconSyncing"]
+
+# Icon Overlay IconError
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE609}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconError"]
+
+# Icon Overlay IconPaused
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE610}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconPaused"]
+
+# Icon Overlay IconLockedByMe
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE611}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByMe"]
+
+# Icon Overlay IconLockedByOthers
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved]
+"{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}"=-
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}]
+
+[-HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{D14BEDD3-4E05-4F2F-B0DE-C0381E6AE612}\InProcServer32]
+
+[-HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayIdentifiers\".SeafileIconLockedByOthers"]
\ No newline at end of file
--- /dev/null
+
+#include "ext-common.h"
+#include "class-factory.h"
+#include "applet-connection.h"
+#include "guids.h"
+#include "log.h"
+#include "ext-utils.h"
+
+#include "shell-ext.h"
+
+volatile LONG g_cRefThisDll = 0; ///< reference count of this DLL.
+HINSTANCE g_hmodThisDll = NULL; ///< handle to this DLL itself.
+int g_cAprInit = 0;
+DWORD g_langid;
+DWORD g_langTimeout = 0;
+HINSTANCE g_hResInst = NULL;
+
+extern "C" int APIENTRY
+DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /* lpReserved */)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ if (g_hmodThisDll == NULL)
+ {
+ // g_csGlobalCOMGuard.Init();
+ }
+
+ // Extension DLL one-time initialization
+ g_hmodThisDll = hInstance;
+ seafile::AppletConnection::instance()->prepare();
+ }
+ else if (dwReason == DLL_PROCESS_DETACH)
+ {
+ // do not clean up memory here:
+ // if an application doesn't release all COM objects
+ // but still unloads the dll, cleaning up ourselves
+ // will lead to crashes.
+ // better to leak some memory than to crash other apps.
+ // sometimes an application doesn't release all COM objects
+ // but still unloads the dll.
+ // in that case, we do it ourselves
+
+ // g_csGlobalCOMGuard.Term();
+ }
+ return 1; // ok
+}
+
+STDAPI DllCanUnloadNow(void)
+{
+ return (g_cRefThisDll == 0 ? S_OK : S_FALSE);
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppvOut)
+{
+ if (ppvOut == 0)
+ return E_POINTER;
+ *ppvOut = NULL;
+
+ if (IsEqualIID(rclsid, CLSID_SEAFILE_SHELLEXT)) {
+ ShellExtClassFactory *pcf = new ShellExtClassFactory;
+ const HRESULT hr = pcf->QueryInterface(riid, ppvOut);
+ if(FAILED(hr))
+ delete pcf;
+ return hr;
+ }
+
+ seafile::RepoInfo::Status status = seafile::RepoInfo::NoStatus;
+ if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_NORMAL)) {
+ // seaf_ext_log ("DllGetClassObject called for ICON_NORMAL!");
+ status = seafile::RepoInfo::Normal;
+ } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_SYNCING)) {
+ // seaf_ext_log ("DllGetClassObject called for ICON_SYNCING!");
+ status = seafile::RepoInfo::Syncing;
+ } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_ERROR)) {
+ // seaf_ext_log ("DllGetClassObject called for ICON_ERROR!");
+ status = seafile::RepoInfo::Error;
+ } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_PAUSED)) {
+ // seaf_ext_log ("DllGetClassObject called for ICON_PAUSED!");
+ status = seafile::RepoInfo::Paused;
+ } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_LOCKED_BY_ME)) {
+ // seaf_ext_log ("DllGetClassObject called for ICON_LOCKED_BY_ME!");
+ status = seafile::RepoInfo::LockedByMe;
+ } else if (IsEqualIID(rclsid, CLSID_SEAFILE_ICON_LOCKED_BY_OTHERS)) {
+ // seaf_ext_log ("DllGetClassObject called for ICON_LOCKED_BY_OTHERS!");
+ status = seafile::RepoInfo::LockedByOthers;
+ }
+
+ if (status != seafile::RepoInfo::NoStatus) {
+ ShellExtClassFactory *pcf = new ShellExtClassFactory(status);
+ const HRESULT hr = pcf->QueryInterface(riid, ppvOut);
+ if(FAILED(hr))
+ delete pcf;
+ return hr;
+ }
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
--- /dev/null
+#ifndef SEAFILE_EXT_EXT_COMMON_H
+#define SEAFILE_EXT_EXT_COMMON_H
+
+// This header should be the first include of each cpp source file
+
+// A workaround for some mingw problem.
+// See http://stackoverflow.com/questions/3445312/swprintf-and-vswprintf-not-declared
+#undef __STRICT_ANSI__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <winsock2.h>
+#include <windows.h>
+#include <ws2tcpip.h>
+#include <commctrl.h>
+
+#include <shlobj.h>
+#include <shlguid.h>
+#include <wininet.h>
+#include <aclapi.h>
+
+#endif // SEAFILE_EXT_EXT_COMMON_H
--- /dev/null
+#include "ext-common.h"
+#include <io.h>
+#include <shellapi.h>
+#include <shlwapi.h>
+#include <fcntl.h>
+#include <psapi.h>
+#include <ctype.h>
+#include <userenv.h>
+
+#include <sstream>
+#include <algorithm>
+#include <memory>
+
+#include "log.h"
+#include "ext-utils.h"
+#include "shell-ext.h"
+
+namespace {
+
+const int kPipeWaitTimeMSec = 1000;
+
+class OverLappedWrapper
+{
+public:
+ OverLappedWrapper() {
+ memset(&ol_, 0, sizeof(ol_));
+ ol_.Offset = ol_.OffsetHigh = 0;
+ HANDLE h_ev = CreateEvent
+ (NULL, /* security attribute */
+ FALSE, /* manual reset */
+ FALSE, /* initial state */
+ NULL); /* event name */
+
+ ol_.hEvent = h_ev;
+ }
+
+ ~OverLappedWrapper() {
+ CloseHandle(ol_.hEvent);
+ }
+
+ OVERLAPPED *get() { return &ol_; }
+
+private:
+ OVERLAPPED ol_;
+};
+
+} // namespace
+
+namespace seafile {
+namespace utils {
+
+
+Mutex::Mutex()
+{
+ handle_ = CreateMutex
+ (NULL, /* securitry attr */
+ FALSE, /* own the mutex immediately after create */
+ NULL); /* name */
+}
+
+Mutex::~Mutex()
+{
+ CloseHandle(handle_);
+}
+
+void Mutex::lock()
+{
+ while (1) {
+ DWORD ret = WaitForSingleObject(handle_, INFINITE);
+ if (ret == WAIT_OBJECT_0)
+ return;
+ }
+}
+
+void Mutex::unlock()
+{
+ ReleaseMutex(handle_);
+}
+
+MutexLocker::MutexLocker(Mutex *mutex)
+ : mu_(mutex)
+{
+ mu_->lock();
+}
+
+MutexLocker::~MutexLocker()
+{
+ mu_->unlock();
+}
+
+
+void regulatePath(char *p)
+{
+ if (!p)
+ return;
+
+ char *s = p;
+ /* Use capitalized C/D/E, etc. */
+ if (s[0] >= 'a')
+ s[0] = toupper(s[0]);
+
+ /* Use / instead of \ */
+ while (*s) {
+ if (*s == '\\')
+ *s = '/';
+ s++;
+ }
+
+ s--;
+ /* strip trailing white spaces and path seperator */
+ while (isspace(*s) || *s == '/') {
+ *s = '\0';
+ s--;
+ }
+}
+
+std::string getHomeDir()
+{
+ static char *home;
+
+ if (home)
+ return home;
+
+ char buf[MAX_PATH] = {'\0'};
+
+ if (!home) {
+ /* Try env variable first. */
+ GetEnvironmentVariable("HOME", buf, MAX_PATH);
+ if (buf[0] != '\0')
+ home = strdup(buf);
+ }
+
+ if (!home) {
+ /* No `HOME' ENV; Try user profile */
+ HANDLE hToken = NULL;
+ DWORD len = MAX_PATH;
+ if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
+ GetUserProfileDirectory (hToken, buf, &len);
+ CloseHandle(hToken);
+ if (buf[0] != '\0')
+ home = strdup(buf);
+ }
+ }
+
+ if (home)
+ regulatePath(home);
+ return home ? home : "";
+}
+
+bool
+doPipeWait (HANDLE pipe, OVERLAPPED *ol, DWORD len)
+{
+ DWORD bytes_rw, result;
+ result = WaitForSingleObject (ol->hEvent, kPipeWaitTimeMSec);
+ if (result == WAIT_OBJECT_0) {
+ if (!GetOverlappedResult(pipe, ol, &bytes_rw, false)
+ || bytes_rw != len) {
+ seaf_ext_log ("async read failed: %s",
+ formatErrorMessage().c_str());
+ return false;
+ }
+ } else if (result == WAIT_TIMEOUT) {
+ seaf_ext_log ("connection timeout");
+ return false;
+
+ } else {
+ seaf_ext_log ("failed to communicate with seafil client: %s",
+ formatErrorMessage().c_str());
+ return false;
+ }
+
+ return true;
+}
+
+bool
+checkLastError()
+{
+ DWORD last_error = GetLastError();
+ if (last_error != ERROR_IO_PENDING && last_error != ERROR_SUCCESS) {
+ if (last_error == ERROR_BROKEN_PIPE || last_error == ERROR_NO_DATA
+ || last_error == ERROR_PIPE_NOT_CONNECTED) {
+ seaf_ext_log ("connection broken with error: %s",
+ formatErrorMessage().c_str());
+ } else {
+ seaf_ext_log ("failed to communicate with seafile client: %s",
+ formatErrorMessage().c_str());
+ }
+ return false;
+ }
+ return true;
+}
+
+bool
+pipeReadN (HANDLE pipe,
+ void *buf,
+ uint32_t len)
+{
+ OverLappedWrapper ol;
+ bool ret= ReadFile(
+ pipe, // handle to pipe
+ buf, // buffer to write from
+ (DWORD)len, // number of bytes to read
+ NULL, // number of bytes read
+ ol.get()); // overlapped (async) IO
+
+ if (!ret && !checkLastError()) {
+ return false;
+ }
+
+ if (!doPipeWait (pipe, ol.get(), (DWORD)len)) {
+ return false;
+ }
+
+ return true;
+}
+
+bool
+pipeWriteN(HANDLE pipe,
+ const void *buf,
+ uint32_t len)
+{
+ OverLappedWrapper ol;
+ bool ret = WriteFile(
+ pipe, // handle to pipe
+ buf, // buffer to write from
+ (DWORD)len, // number of bytes to write
+ NULL, // number of bytes written
+ ol.get()); // overlapped (async) IO
+
+ if (!ret && !checkLastError()) {
+ return false;
+ }
+
+ if (!doPipeWait(pipe, ol.get(), (DWORD)len))
+ return false;
+
+ return true;
+}
+
+bool doInThread(LPTHREAD_START_ROUTINE func, void *data)
+{
+ DWORD tid = 0;
+ HANDLE thread = CreateThread
+ (NULL, /* security attr */
+ 0, /* stack size, 0 for default */
+ func, /* start address */
+ (void *)data, /* param*/
+ 0, /* creation flags */
+ &tid); /* thread ID */
+
+ if (!thread) {
+ seaf_ext_log ("failed to create thread");
+ return false;
+ }
+
+ CloseHandle(thread);
+ return true;
+}
+
+// http://stackoverflow.com/questions/3006229/get-a-text-from-the-error-code-returns-from-the-getlasterror-function
+std::string formatErrorMessage()
+{
+ DWORD error_code = ::GetLastError();
+ if (error_code == 0) {
+ return "no error";
+ }
+ char buf[256] = {0};
+ ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ error_code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buf,
+ sizeof(buf) - 1,
+ NULL);
+ return buf;
+}
+
+std::vector<std::string> split(const std::string &s, char delim)
+{
+ std::vector<std::string> elems;
+ std::stringstream ss(s);
+ std::string item;
+ while (std::getline(ss, item, delim) && !item.empty()) {
+ elems.push_back(item);
+ }
+ return elems;
+}
+
+std::string normalizedPath(const std::string& path)
+{
+ std::string p = path;
+ std::replace(p.begin(), p.end(), '\\', '/');
+ while (!p.empty() && p[p.size() - 1] == '/') {
+ p = p.substr(0, p.size() - 1);
+ }
+ return p;
+}
+
+uint64_t currentMSecsSinceEpoch()
+{
+ SYSTEMTIME st;
+ FILETIME ft;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+
+ ULARGE_INTEGER u;
+ u.LowPart = ft.dwLowDateTime;
+ u.HighPart = ft.dwHighDateTime;
+
+ // See http://stackoverflow.com/questions/6161776/convert-windows-filetime-to-second-in-unix-linux
+#define TICKS_PER_MSEC 10000
+#define EPOCH_DIFFERENCE 11644473600000LL
+ uint64_t temp;
+ temp = u.QuadPart / TICKS_PER_MSEC; //convert from 100ns intervals to milli seconds;
+ temp = temp - EPOCH_DIFFERENCE; //subtract number of seconds between epochs
+ return temp;
+}
+
+std::string splitPath(const std::string& path, int *pos)
+{
+ if (path.size() == 0) {
+ return "";
+ }
+
+ std::string p = normalizedPath(path);
+ while (p.size() > 1 && p[-1] == '/') {
+ p = p.substr(0, p.size() - 1);
+ }
+ if (p.size() == 1) {
+ return p;
+ }
+
+ *pos = p.rfind("/");
+ return p;
+}
+
+
+std::string getParentPath(const std::string& path)
+{
+ int pos;
+ std::string p = splitPath(path, &pos);
+ if (p.size() <= 1) {
+ return p;
+ }
+
+ if (pos == -1)
+ return "";
+ if (pos == 0)
+ return "/";
+ return p.substr(0, pos);
+}
+
+std::string getBaseName(const std::string& path)
+{
+ int pos;
+ std::string p = splitPath(path, &pos);
+ if (p.size() <= 1) {
+ return p;
+ }
+
+ if (pos == -1) {
+ return p;
+ }
+ return p.substr(pos, p.size() - pos);
+}
+
+std::string getThisDllPath()
+{
+ static char module_filename[MAX_PATH] = { 0 };
+
+ if (module_filename[0] == '\0') {
+ DWORD module_size;
+ module_size = GetModuleFileName(
+ g_hmodThisDll, module_filename, MAX_PATH);
+ if (!module_size)
+ return "";
+
+ normalizedPath(module_filename);
+ }
+
+ return module_filename;
+}
+
+std::string getThisDllFolder()
+{
+ std::string dll = getThisDllPath();
+
+ return dll.empty() ? "" : getParentPath(dll);
+}
+
+wchar_t *localeToWString(const std::string& src)
+{
+ wchar_t dst[4096];
+ int len;
+
+ len = MultiByteToWideChar
+ (CP_ACP, /* multibyte code page */
+ 0, /* flags */
+ src.c_str(), /* src */
+ -1, /* src len, -1 for all includes \0 */
+ dst, /* dst */
+ sizeof(dst) / sizeof(wchar_t)); /* dst buf len */
+
+ if (len <= 0) {
+ return NULL;
+ }
+
+ return wcsdup(dst);
+}
+
+
+std::string wStringToLocale(const wchar_t *src)
+{
+ char dst[4096];
+ int len;
+
+ len = WideCharToMultiByte
+ (CP_ACP, /* multibyte code page */
+ 0, /* flags */
+ src, /* src */
+ -1, /* src len, -1 for all includes \0 */
+ dst, /* dst */
+ sizeof(dst), /* dst buf len */
+ NULL, /* default char */
+ NULL); /* BOOL flag indicates default char is used */
+
+ if (len <= 0) {
+ return "";
+ }
+
+ return dst;
+}
+
+std::string wStringToUtf8(const wchar_t *src)
+{
+ char dst[4096];
+ int len;
+
+ len = WideCharToMultiByte
+ (CP_UTF8, /* multibyte code page */
+ 0, /* flags */
+ src, /* src */
+ -1, /* src len, -1 for all includes \0 */
+ dst, /* dst */
+ sizeof(dst), /* dst buf len */
+ NULL, /* default char */
+ NULL); /* BOOL flag indicates default char is used */
+
+ if (len <= 0) {
+ return "";
+ }
+
+ return dst;
+}
+
+wchar_t *utf8ToWString(const std::string& src)
+{
+ wchar_t dst[4096];
+ int len;
+
+ len = MultiByteToWideChar
+ (CP_UTF8, /* multibyte code page */
+ 0, /* flags */
+ src.c_str(), /* src */
+ -1, /* src len, -1 for all includes \0 */
+ dst, /* dst */
+ sizeof(dst) / sizeof(wchar_t)); /* dst buf len */
+
+ if (len <= 0) {
+ return NULL;
+ }
+
+ return wcsdup(dst);
+}
+
+bool isShellExtEnabled()
+{
+ // TODO: This function is called very frequently. Consider caching the
+ // result in memory for a few seconds, and only query the registry after
+ // that.
+ HKEY root = HKEY_CURRENT_USER;
+ HKEY parent_key;
+ wchar_t *software_seafile = localeToWString("Software\\Seafile");
+ LONG result = RegOpenKeyExW(root,
+ software_seafile,
+ 0L,
+ KEY_ALL_ACCESS,
+ &parent_key);
+ free(software_seafile);
+ if (result != ERROR_SUCCESS) {
+ return true;
+ }
+
+ char buf[MAX_PATH] = {0};
+ DWORD len = sizeof(buf);
+ wchar_t *shell_ext_disabled = localeToWString("ShellExtDisabled");
+ result = RegQueryValueExW (parent_key,
+ shell_ext_disabled,
+ NULL, /* reserved */
+ NULL, /* output type */
+ (LPBYTE)buf, /* output data */
+ &len); /* output length */
+ RegCloseKey(parent_key);
+ free(shell_ext_disabled);
+
+ return result != ERROR_SUCCESS;
+}
+
+
+} // namespace utils
+} // namespace seafile
--- /dev/null
+#ifndef SEAFILE_EXTENSION_EXT_UTILS_H
+#define SEAFILE_EXTENSION_EXT_UTILS_H
+
+#include <string>
+#include <vector>
+#include <stdint.h>
+
+namespace seafile {
+namespace utils {
+
+class Mutex {
+public:
+ Mutex();
+ ~Mutex();
+
+ void lock();
+ void unlock();
+
+private:
+ Mutex(const Mutex& rhs);
+ HANDLE handle_;
+};
+
+class MutexLocker {
+public:
+ MutexLocker(Mutex *mutex);
+ ~MutexLocker();
+
+private:
+ Mutex *mu_;
+};
+
+std::string getHomeDir();
+
+/**
+ * Translate the error code of GetLastError() to a human readable message.
+ */
+std::string formatErrorMessage();
+
+bool pipeReadN (HANDLE hPipe,
+ void *buf,
+ uint32_t len);
+
+bool pipeWriteN (HANDLE hPipe,
+ const void *buf,
+ uint32_t len);
+
+bool doInThread(LPTHREAD_START_ROUTINE func, void *data);
+
+std::vector<std::string> split(const std::string &s, char delim);
+
+std::string normalizedPath(const std::string& path);
+
+uint64_t currentMSecsSinceEpoch();
+
+wchar_t *localeToWString(const std::string& src);
+std::string wStringToLocale(const wchar_t *src);
+
+wchar_t *utf8ToWString(const std::string& src);
+std::string wStringToUtf8(const wchar_t *src);
+
+std::string getBaseName(const std::string& path);
+std::string getParentPath(const std::string& path);
+
+std::string getThisDllFolder();
+std::string getThisDllPath();
+
+bool isShellExtEnabled();
+
+} // namespace utils
+} // namespace seafile
+
+#endif // SEAFILE_EXTENSION_EXT_UTILS_H
--- /dev/null
+// The class IDs of these Shell extension class.
+//
+// class ids:
+//
+// D14BEDD3-4E05-4F2F-B0DE-C0381E6AE606
+//
+//
+
+DEFINE_GUID(CLSID_SEAFILE_SHELLEXT,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x06);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_NORMAL,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x07);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_SYNCING,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x08);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_ERROR,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x09);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_PAUSED,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x10);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_LOCKED_BY_ME,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x11);
+
+DEFINE_GUID(CLSID_SEAFILE_ICON_LOCKED_BY_OTHERS,0xd14bedd3, 0x4e05, 0x4f2f, 0xb0, 0xde, 0xc0, 0x38, 0x1e, 0x6a, 0xe6, 0x12);
--- /dev/null
+#include "ext-common.h"
+#include "ext-utils.h"
+
+#include <string>
+#include <map>
+#include <memory>
+
+using std::string;
+
+namespace {
+
+string getWin32Locale()
+{
+ LCID lcid;
+ char iso639[10];
+
+ lcid = GetThreadLocale ();
+
+ if (!GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)))
+ return "C";
+
+ return iso639;
+}
+
+class I18NHelper {
+public:
+ static I18NHelper *instance();
+
+ string getString(const string& src) const;
+
+private:
+ I18NHelper();
+ static I18NHelper *singleton_;
+
+ void initChineseDict();
+ void initGermanDict();
+
+ std::map<string, string> lang_dict_;
+};
+
+
+I18NHelper* I18NHelper::singleton_;
+
+I18NHelper *I18NHelper::instance() {
+ if (!singleton_) {
+ singleton_ = new I18NHelper();
+ }
+ return singleton_;
+}
+
+void I18NHelper::initChineseDict()
+{
+ lang_dict_["get seafile download link"] = "获取共享链接";
+ lang_dict_["get seafile internal link"] = "获取内部链接";
+ lang_dict_["lock this file"] = "锁定该文件";
+ lang_dict_["unlock this file"] = "解锁该文件";
+ lang_dict_["share to a user"] = "共享给其他用户";
+ lang_dict_["share to a group"] = "共享给群组";
+ lang_dict_["view file history"] = "查看文件历史";
+}
+
+void I18NHelper::initGermanDict()
+{
+ lang_dict_["get seafile download link"] = "Freigabelink erstellen";
+ lang_dict_["get seafile internal link"] = "Internen Link erstellen";
+ lang_dict_["lock this file"] = "Datei sperren";
+ lang_dict_["unlock this file"] = "Datei entsperren";
+ lang_dict_["share to a user"] = "Freigabe für Benutzer/in";
+ lang_dict_["share to a group"] = "Freigabe für Gruppe";
+ lang_dict_["view file history"] = "Vorgängerversionen";
+}
+
+I18NHelper::I18NHelper()
+{
+ string locale = getWin32Locale();
+ if (locale == "zh") {
+ initChineseDict();
+ } else if (locale == "de") {
+ initGermanDict();
+ }
+}
+
+string I18NHelper::getString(const string& src) const
+{
+ auto value = lang_dict_.find(src);
+ return value != lang_dict_.end() ? value->second : src;
+}
+
+} // namespace
+
+namespace seafile {
+
+string getString(const string& src)
+{
+ string value = I18NHelper::instance()->getString(src);
+ std::unique_ptr<wchar_t[]> value_w(utils::utf8ToWString(value));
+ return utils::wStringToLocale(value_w.get());
+}
+
+}
--- /dev/null
+#ifndef SEAFILE_EXT_I18N_H
+#define SEAFILE_EXT_I18N_H
+
+#include <string>
+
+namespace seafile {
+
+std::string getString(const std::string& src);
+
+} // namespace seafile
+
+#endif // SEAFILE_EXT_I18N_H
--- /dev/null
+#include "ext-common.h"
+#include "ext-utils.h"
+#include "shell-ext.h"
+#include "log.h"
+#include "commands.h"
+
+#include <string>
+
+namespace utils = seafile::utils;
+
+// "The Shell calls IShellIconOverlayIdentifier::GetOverlayInfo to request the
+// location of the handler's icon overlay. The icon overlay handler returns
+// the name of the file containing the overlay image, and its index within
+// that file. The Shell then adds the icon overlay to the system image list."
+
+STDMETHODIMP ShellExt::GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, int* pIndex, DWORD* pdwFlags)
+{
+ // seaf_ext_log ("GetOverlayInfo called for icon type %d!", (int)status_);
+
+ std::string dll = utils::getThisDllPath();
+
+ std::unique_ptr<wchar_t[]> ico(utils::localeToWString(dll));
+ int wlen = wcslen(ico.get());
+ if (wlen + 1 > cchMax)
+ return S_FALSE;
+
+ wmemcpy(pwszIconFile, ico.get(), wlen + 1);
+
+ *pdwFlags = ISIOI_ICONFILE | ISIOI_ICONINDEX;
+
+ *pIndex = (int)status_ - 1;
+
+ return S_OK;
+}
+
+STDMETHODIMP ShellExt::GetPriority(int *priority)
+{
+ /* The priority value can be 0 ~ 100, with 0 be the highest */
+ *priority = seafile::RepoInfo::N_Status - status_;
+ return S_OK;
+}
+
+
+// "Before painting an object's icon, the Shell passes the object's name to
+// each icon overlay handler's IShellIconOverlayIdentifier::IsMemberOf
+// method. If a handler wants to have its icon overlay displayed,
+// it returns S_OK. The Shell then calls the handler's
+// IShellIconOverlayIdentifier::GetOverlayInfo method to determine which icon
+// to display."
+
+STDMETHODIMP ShellExt::IsMemberOf(LPCWSTR path_w, DWORD attr)
+{
+ if (!seafile::utils::isShellExtEnabled()) {
+ return S_FALSE;
+ }
+
+ std::string path = utils::wStringToUtf8(path_w);
+ if (!path.size()) {
+ seaf_ext_log ("convert to char failed");
+ return S_FALSE;
+ }
+
+ // seaf_ext_log ("IsMemberOf called for %s, is dir: %s", path.c_str(),
+ // (attr & FILE_ATTRIBUTE_DIRECTORY) ? "yes": "no");
+
+ /* If length of path is shorter than 3, it should be a drive path,
+ * such as C:\ , which should not be a repo folder ; And the
+ * current folder being displayed must be "My Computer". If we
+ * don't return quickly, it will lag the display.
+ */
+ if (path.size() <= 3) {
+ return S_FALSE;
+ }
+
+ // if (access(path.c_str(), F_OK) < 0 ||
+ // !(GetFileAttributes(path.c_str()) & FILE_ATTRIBUTE_DIRECTORY)) {
+ // return S_FALSE;
+ // }
+
+ std::string path_in_repo;
+ seafile::RepoInfo repo;
+ if (!pathInRepo(path, &path_in_repo, &repo)) {
+ // seaf_ext_log ("pathInRepo returns false for %s\n", path.c_str());
+ return S_FALSE;
+ }
+
+ // seaf_ext_log ("path in repo: %s\n", path_in_repo.c_str());
+
+ if (path_in_repo.size() <= 1) {
+ // it's a repo top folder
+ path_in_repo = "";
+ }
+
+ // Now we know it's a file inside the repo
+
+ // TODO: Improve this if we later make the extension<->applet communication full duplex
+ // if (repo.status == seafile::RepoInfo::Paused) {
+ // return S_FALSE;
+ // }
+
+ // if (repo.status == seafile::RepoInfo::Normal && repo.status == status_) {
+ // return S_OK;
+ // }
+
+ // Then check the file status.
+ seafile::RepoInfo::Status status = getRepoFileStatus(
+ repo.repo_id, path_in_repo, attr & FILE_ATTRIBUTE_DIRECTORY);
+
+ if (status == seafile::RepoInfo::Paused && !path_in_repo.empty()) {
+ return S_FALSE;
+ }
+ if (status == status_ || (status_ == seafile::RepoInfo::Paused && status == seafile::RepoInfo::ReadOnly)) {
+ // seaf_ext_log ("[ICON] file icon %d: %s", (int)status_, path.c_str());
+ return S_OK;
+ }
+
+ return S_FALSE;
+}
--- /dev/null
+#include "ext-common.h"
+#include <time.h>
+#include <stdarg.h>
+
+#include "ext-utils.h"
+#include "log.h"
+
+namespace {
+
+static FILE *log_fp;
+
+std::string getLogPath()
+{
+ std::string home = seafile::utils::getHomeDir();
+ if (home.empty())
+ return "";
+
+ return home + "/seaf_ext.log";
+}
+
+
+}
+
+void
+seaf_ext_log_start ()
+{
+ if (log_fp)
+ return;
+
+ std::string log_path = getLogPath();
+ if (!log_path.empty())
+ log_fp = fopen (log_path.c_str(), "a");
+
+ if (log_fp) {
+ seaf_ext_log ("\n----------------------------------\n"
+ "log file initialized: 4.1.0 %s"
+ "\n----------------------------------\n"
+ , log_path.c_str());
+ } else {
+ fprintf (stderr, "[LOG] Can't init log file %s\n", log_path.c_str());
+ }
+}
+
+void
+seaf_ext_log_stop ()
+{
+ if (log_fp) {
+ fclose (log_fp);
+ log_fp = NULL;
+ }
+}
+
+void
+seaf_ext_log_aux (const char *format, ...)
+{
+ if (!log_fp)
+ seaf_ext_log_start();
+
+ if (log_fp) {
+ va_list params;
+ char buffer[1024];
+ size_t length = 0;
+
+ va_start(params, format);
+ length = vsnprintf(buffer, sizeof(buffer), format, params);
+ va_end(params);
+
+ /* Write the timestamp. */
+ time_t t;
+ struct tm *tm;
+ char buf[256];
+
+ t = time(NULL);
+ tm = localtime(&t);
+ strftime (buf, 256, "[%y/%m/%d %H:%M:%S] ", tm);
+
+ fputs (buf, log_fp);
+ if (fwrite(buffer, sizeof(char), length, log_fp) < length)
+ return;
+
+ fputc('\n', log_fp);
+ fflush(log_fp);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_EXTENSION_LOG_H
+#define SEAFILE_CLIENT_EXTENSION_LOG_H
+
+void seaf_ext_log_start();
+void seaf_ext_log_stop();
+
+void seaf_ext_log_aux(const char *format, ...);
+
+#define seaf_ext_log(format, ... ) \
+ seaf_ext_log_aux("%s(line %d) %s: " format, \
+ __FILE__, __LINE__, __func__, ##__VA_ARGS__) \
+
+
+#endif // SEAFILE_CLIENT_EXTENSION_LOG_H
--- /dev/null
+LIBRARY seafile_shell_ext
+EXPORTS
+DllMain
+DllCanUnloadNow PRIVATE
+DllGetClassObject PRIVATE
--- /dev/null
+1 ICON DISCARDABLE "paused.ico"
+2 ICON DISCARDABLE "normal.ico"
+3 ICON DISCARDABLE "syncing.ico"
+4 ICON DISCARDABLE "error.ico"
+5 ICON DISCARDABLE "locked-by-me.ico"
+6 ICON DISCARDABLE "locked-by-others.ico"
--- /dev/null
+// Initialize GUIDs (should be done only and at-least once per DLL/EXE)
+#include <initguid.h>
+#include "guids.h"
+
+#include "ext-common.h"
+#include "ext-utils.h"
+#include "commands.h"
+#include "log.h"
+#include "shell-ext.h"
+
+namespace utils = seafile::utils;
+
+namespace {
+
+const int kWorktreeCacheExpireMSecs = 3 * 1000;
+
+} // namespace
+
+std::unique_ptr<seafile::RepoInfoList> ShellExt::repos_cache_;
+uint64_t ShellExt::cache_ts_;
+
+// *********************** ShellExt *************************
+ShellExt::ShellExt(seafile::RepoInfo::Status status)
+ : main_menu_(0),
+ index_(0),
+ first_(0),
+ last_(0)
+{
+ m_cRef = 0L;
+ InterlockedIncrement(&g_cRefThisDll);
+
+ sub_menu_ = CreateMenu();
+ next_active_item_ = 0;
+ status_ = status;
+
+ // INITCOMMONCONTROLSEX used = {
+ // sizeof(INITCOMMONCONTROLSEX),
+ // ICC_LISTVIEW_CLASSES | ICC_WIN95_CLASSES | ICC_BAR_CLASSES | ICC_USEREX_CLASSES
+ // };
+ // InitCommonControlsEx(&used);
+}
+
+ShellExt::~ShellExt()
+{
+ InterlockedDecrement(&g_cRefThisDll);
+}
+
+STDMETHODIMP ShellExt::QueryInterface(REFIID riid, LPVOID FAR *ppv)
+{
+ if (ppv == 0)
+ return E_POINTER;
+
+ *ppv = NULL;
+
+ if (IsEqualIID(riid, IID_IShellExtInit) || IsEqualIID(riid, IID_IUnknown)) {
+ *ppv = static_cast<LPSHELLEXTINIT>(this);
+ }
+ else if (IsEqualIID(riid, IID_IContextMenu)) {
+ *ppv = static_cast<LPCONTEXTMENU>(this);
+ }
+ else if (IsEqualIID(riid, IID_IShellIconOverlayIdentifier)) {
+ *ppv = static_cast<IShellIconOverlayIdentifier*>(this);
+ }
+ // else if (IsEqualIID(riid, IID_IContextMenu3))
+ // {
+ // *ppv = static_cast<LPCONTEXTMENU3>(this);
+ // }
+ else
+ {
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) ShellExt::AddRef()
+{
+ return ++m_cRef;
+}
+
+STDMETHODIMP_(ULONG) ShellExt::Release()
+{
+ if (--m_cRef)
+ return m_cRef;
+
+ delete this;
+
+ return 0L;
+}
+
+bool ShellExt::getReposList(seafile::RepoInfoList *wts)
+{
+ seafile::utils::MutexLocker lock(&repos_cache_mutex_);
+
+ uint64_t now = utils::currentMSecsSinceEpoch();
+ if (repos_cache_ && now < cache_ts_ + kWorktreeCacheExpireMSecs) {
+ *wts = *(repos_cache_.get());
+ // seaf_ext_log("use cached repos list!");
+ return true;
+ }
+
+ // no cached worktree list, send request to seafile client
+ seafile::ListReposCommand cmd;
+ seafile::RepoInfoList repos;
+ if (!cmd.sendAndWait(&repos)) {
+ // seaf_ext_log("ListReposCommand returned false!");
+ return false;
+ }
+
+ cache_ts_ = utils::currentMSecsSinceEpoch();
+ repos_cache_.reset(new seafile::RepoInfoList(repos));
+
+ *wts = repos;
+ return true;
+}
+
+bool ShellExt::pathInRepo(const std::string& path,
+ std::string *path_in_repo,
+ seafile::RepoInfo *repo)
+{
+ seafile::RepoInfoList repos;
+ if (!getReposList(&repos)) {
+ return false;
+ }
+ std::string p = utils::normalizedPath(path);
+
+ for (size_t i = 0; i < repos.size(); i++) {
+ std::string wt = repos[i].worktree;
+ // seaf_ext_log ("work tree is %s, path is %s\n", wt.c_str(), p.c_str());
+ if (p.size() >= wt.size() && p.substr(0, wt.size()) == wt) {
+ if (p.size() > wt.size() && p[wt.size()] != '/') {
+ continue;
+ }
+ *path_in_repo = p.substr(wt.size(), p.size() - wt.size());
+ if (repo) {
+ *repo = repos[i];
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ShellExt::isRepoTopDir(const std::string& path)
+{
+ seafile::RepoInfoList repos;
+ if (!getReposList(&repos)) {
+ return false;
+ }
+
+ std::string p = utils::normalizedPath(path);
+ for (size_t i = 0; i < repos.size(); i++) {
+ std::string wt = repos[i].worktree;
+ if (p == wt) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+seafile::RepoInfo ShellExt::getRepoInfoByPath(const std::string& path)
+{
+ seafile::RepoInfoList repos;
+ if (!getReposList(&repos)) {
+ return seafile::RepoInfo();
+ }
+
+ std::string p = utils::normalizedPath(path);
+ for (size_t i = 0; i < repos.size(); i++) {
+ std::string wt = repos[i].worktree;
+ if (p == wt) {
+ return repos[i];
+ }
+ }
+
+ return seafile::RepoInfo();
+}
+
+seafile::RepoInfo::Status
+ShellExt::getRepoFileStatus(const std::string& repo_id,
+ const std::string& path_in_repo,
+ bool isdir)
+{
+ // TODO: get the files under the same folder in a single command to reduce overhead
+ seafile::GetFileStatusCommand cmd(repo_id, path_in_repo, isdir);
+ seafile::RepoInfo::Status status;
+ if (!cmd.sendAndWait(&status)) {
+ return seafile::RepoInfo::NoStatus;
+ }
+
+ return status;
+}
--- /dev/null
+#ifndef SEAFILE_EXT_SHELL_EXT_H
+#define SEAFILE_EXT_SHELL_EXT_H
+
+#include <string>
+#include <memory>
+#include <vector>
+#include "commands.h"
+#include "ext-utils.h"
+
+extern volatile LONG g_cRefThisDll; // Reference count of this DLL.
+extern HINSTANCE g_hmodThisDll; // Instance handle for this DLL
+extern HINSTANCE g_hResInst;
+
+struct SeafileMenuItem {
+ std::string text; /* displayed in the menu */
+ std::string help; /* displayed in the status bar */
+};
+
+class ShellExt : public IContextMenu3,
+ IShellIconOverlayIdentifier,
+ IShellExtInit
+{
+
+protected:
+ ULONG m_cRef;
+
+ // IContextMenu2 wrapper functions to catch exceptions and send crash reports
+ STDMETHODIMP QueryContextMenu_Wrap(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
+ STDMETHODIMP InvokeCommand_Wrap(LPCMINVOKECOMMANDINFO lpcmi);
+ STDMETHODIMP GetCommandString_Wrap(UINT_PTR idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax);
+ STDMETHODIMP HandleMenuMsg_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ // IContextMenu3 wrapper functions to catch exceptions and send crash reports
+ STDMETHODIMP HandleMenuMsg2_Wrap(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult);
+
+ // IShellExtInit wrapper functions to catch exceptions and send crash reports
+ STDMETHODIMP Initialize_Wrap(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID);
+
+ seafile::RepoInfo::Status status_;
+
+public:
+ ShellExt(seafile::RepoInfo::Status status = seafile::RepoInfo::NoStatus);
+ virtual ~ShellExt();
+
+ // IUnknown members
+ STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // IContextMenu2 members
+ STDMETHODIMP QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
+ STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
+ STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT FAR *reserved, LPSTR pszName, UINT cchMax);
+ STDMETHODIMP HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ // IContextMenu3 members
+ STDMETHODIMP HandleMenuMsg2(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *pResult);
+
+ // IShellIconOverlayIdentifier members
+ STDMETHODIMP GetOverlayInfo(LPWSTR pwszIconFile, int cchMax, int *pIndex, DWORD *pdwFlags);
+ STDMETHODIMP GetPriority(int *pPriority);
+ STDMETHODIMP IsMemberOf(LPCWSTR pwszPath, DWORD dwAttrib);
+
+ // IShellExtInit methods
+ STDMETHODIMP Initialize(LPCITEMIDLIST pIDFolder, LPDATAOBJECT pDataObj, HKEY hKeyID);
+
+private:
+ enum MenuOp {
+ GetShareLink,
+ GetInternalLink,
+ LockFile,
+ UnlockFile,
+ ShareToUser,
+ ShareToGroup,
+ ShowHistory,
+ };
+
+ void buildSubMenu(const seafile::RepoInfo& repo,
+ const std::string& path_in_repo);
+ MENUITEMINFO createMenuItem(const std::string& text);
+ bool insertMainMenu();
+ void insertSubMenuItem(const std::string& text, MenuOp op);
+ void tweakMenu(HMENU menu);
+
+ bool getReposList(seafile::RepoInfoList *wts);
+ bool pathInRepo(const std::string& path, std::string *path_in_repo, seafile::RepoInfo *repo=0);
+ bool isRepoTopDir(const std::string& path);
+ seafile::RepoInfo getRepoInfoByPath(const std::string& path);
+ seafile::RepoInfo::Status getRepoFileStatus(const std::string& repo_id,
+ const std::string& path_in_repo,
+ bool isdir);
+ /* the file/dir current clicked on */
+ std::string path_;
+
+ static std::unique_ptr<seafile::RepoInfoList> repos_cache_;
+ static uint64_t cache_ts_;
+ seafile::utils::Mutex repos_cache_mutex_;
+
+ /* The main menu */
+ HMENU main_menu_;
+ /* The popup seafile submenu */
+ HMENU sub_menu_;
+ UINT index_;
+ UINT first_;
+ UINT last_;
+ UINT next_active_item_;
+
+ std::vector<MenuOp> active_menu_items_;
+};
+
+#endif // SEAFILE_EXT_SHELL_EXT_H
--- /dev/null
+BasedOnStyle: LLVM
+Standard: Cpp11
+IndentWidth: 4
+TabWidth: 4
--- /dev/null
+[main]
+host = https://www.transifex.com
+
+[seafile-client.finder-sync]
+file_filter = <lang>.lproj/Localizable.strings
+source_file = en.lproj/Localizable.strings
+source_lang = en
+type = STRINGS
+
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
+
+PROJECT(seafile-fsplugin)
+SET(PROJECT_VERSION "1.0.0")
+
+IF (NOT (${CMAKE_BUILD_TYPE} MATCHES Release))
+ SET(CMAKE_BUILD_TYPE Debug)
+ENDIF()
+
+SET(CODESIGN_CERTIFICATE "-" CACHE STRING "the certificate to sign code")
+
+MESSAGE(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+
+IF (NOT APPLE)
+ MESSAGE(FATAL_ERROR "Support only on OS X")
+ENDIF()
+
+IF (NOT CMAKE_GENERATOR STREQUAL Xcode)
+ MESSAGE(FATAL_ERROR "Support only for Xcode generator")
+ENDIF()
+
+## Build with warnings
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wsign-compare -Wno-long-long -Wno-unused-parameter -Woverloaded-virtual")
+
+## Find the dependencies
+
+FIND_LIBRARY(AppKit_LIBRARY AppKit)
+FIND_LIBRARY(FinderSync_LIBRARY FinderSync)
+FIND_LIBRARY(PlugInKit_LIBRARY PlugInKit
+ PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks/)
+
+if (NOT PlugInKit_LIBRARY)
+ MESSAGE(FATAL_ERROR "PlugInKit not found")
+endif()
+
+ADD_DEFINITIONS(-fapplication-extension -fmodules)
+SET(CMAKE_EXE_LINKER_FLAGS "-fapplication-extension -e _NSExtensionMain -fobjc-arc -fobjc-link-runtime ${CMAKE_EXE_LINKER_FLAGS}")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
+SET(FSPLUGIN_SRC
+ ../src/utils/stl.cpp
+ ../src/utils/stl.h
+ FinderSync.mm
+ FinderSyncClient.mm
+ )
+
+## update en.lproj
+ADD_CUSTOM_TARGET(update-lproj
+ COMMAND genstrings -o en.lproj ${FSPLUGIN_SRC}
+ DEPENDS ${FSPLUGIN_SRC})
+
+ADD_EXECUTABLE(seafile-finder-sync MACOSX_BUNDLE
+ ${FSPLUGIN_SRC}
+)
+
+SET_TARGET_PROPERTIES(seafile-finder-sync PROPERTIES
+ OUTPUT_NAME "Seafile FinderSync"
+ MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
+ XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.10"
+ XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@executable_path/../Frameworks @executable_path/../../../../Frameworks"
+ XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES"
+ XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11"
+ XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++"
+ XCODE_ATTRIBUTE_DEVELOPMENT_LANGUAGE "English"
+ XCODE_ATTRIBUTE_LOCALIZED_RESOURCES_FOLDER_PATH "Seafile FinderSync.appex/English.lproj"
+ XCODE_ATTRIBUTE_INFOSTRINGS_PATH "Seafile FinderSync.appex/English.lproj/InfoPlist.strings"
+ XCODE_ATTRIBUTE_UNLOCALIZED_RESOURCES_FOLDER_PATH "Seafile FinderSync.appex"
+ )
+
+TARGET_LINK_LIBRARIES(seafile-finder-sync
+ ${FinderSync_LIBRARY}
+ ${PlugInKit_LIBRARY}
+ ${AppKit_LIBRARY}
+)
+
+### rename to Seafile Client.appex and copy related resource files
+
+SET(BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/Seafile FinderSync.app")
+SET(TARGET_DIR "${CMAKE_CURRENT_BINARY_DIR}/Seafile FinderSync.appex")
+
+ADD_CUSTOM_TARGET(clean_old_target
+ COMMAND ${CMAKE_COMMAND} -E remove -f ${TARGET_DIR}
+ )
+ADD_CUSTOM_TARGET(copy_fsplugin
+ COMMAND ${CMAKE_COMMAND} -E copy_directory ${BUILD_DIR} ${TARGET_DIR}
+ DEPENDS seafile-finder-sync clean_old_target
+ )
+
+ADD_CUSTOM_TARGET(create_resource_dir
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET_DIR}/Contents/Resources
+ DEPENDS copy_fsplugin
+ )
+ADD_CUSTOM_TARGET(copy_resources_icns
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/../seafile.icns ${TARGET_DIR}/Contents/Resources/
+ COMMAND ${CMAKE_COMMAND} -E copy status-done.icns ${TARGET_DIR}/Contents/Resources/
+ COMMAND ${CMAKE_COMMAND} -E copy status-error.icns ${TARGET_DIR}/Contents/Resources/
+ COMMAND ${CMAKE_COMMAND} -E copy status-syncing.icns ${TARGET_DIR}/Contents/Resources/
+ COMMAND ${CMAKE_COMMAND} -E copy status-ignored.icns ${TARGET_DIR}/Contents/Resources/
+ COMMAND ${CMAKE_COMMAND} -E copy status-locked.icns ${TARGET_DIR}/Contents/Resources/
+ COMMAND ${CMAKE_COMMAND} -E copy status-locked-by-me.icns ${TARGET_DIR}/Contents/Resources/
+ DEPENDS create_resource_dir
+ )
+ADD_CUSTOM_TARGET(copy_resources_lproj
+ DEPENDS create_resource_dir)
+
+SET(FSPLUGIN_LANGS)
+file(GLOB FSPLUGIN_LPROJS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.lproj")
+
+FOREACH(LPROJ ${FSPLUGIN_LPROJS})
+ STRING(REGEX REPLACE "^.*/([a-z]+)\\.lproj/.*$" "\\1" _LANG ${LPROJ})
+ LIST(FIND FSPLUGIN_LANGS "${_LANG}" _INDEX)
+ IF(_INDEX EQUAL -1)
+ LIST(APPEND FSPLUGIN_LANGS ${_LANG})
+ ADD_CUSTOM_TARGET(copy_resources_lproj_${_LANG}
+ COMMAND cp -r ${_LANG} ${TARGET_DIR}/Contents/Resources/
+ DEPENDS create_resource_dir)
+ ADD_DEPENDENCIES(copy_resources_lproj copy_resources_lproj_${_LANG})
+ ENDIF(_INDEX EQUAL -1)
+ENDFOREACH()
+
+### codesign
+
+FIND_PROGRAM(CODESIGN codesign)
+
+ADD_CUSTOM_TARGET(codesign ALL
+ COMMAND ${CODESIGN} --force --sign ${CODESIGN_CERTIFICATE} --entitlements ${CMAKE_CURRENT_SOURCE_DIR}/seafile-fsplugin.entitlements ${TARGET_DIR}
+ DEPENDS copy_resources_icns copy_resources_lproj
+ )
--- /dev/null
+//
+// FinderSync.h
+// seafile-client-fsplugin
+//
+// Created by Chilledheart on 1/10/15.
+// Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <FinderSync/FinderSync.h>
+
+@interface FinderSync : FIFinderSync
+- (void)updateWatchSet:(void *)ptr_to_new_repos;
+- (void)updateFileStatus:(const char *)repo_id
+ path:(const char *)path
+ status:(uint32_t)status;
+@end
--- /dev/null
+//
+// FinderSync.m
+// seafile-client-fsplugin
+//
+// Created by Chilledheart on 1/10/15.
+// Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import "FinderSync.h"
+#import "FinderSyncClient.h"
+#include <utility>
+#include <map>
+#include <unordered_map>
+#include <algorithm>
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+@interface FinderSync ()
+
+@property(readwrite, nonatomic, strong) NSTimer *update_watch_set_timer_;
+@property(readwrite, nonatomic, strong) NSTimer *update_file_status_timer_;
+@property(readwrite, nonatomic, strong) dispatch_queue_t client_command_queue_;
+@end
+
+static const char *const kClientCommandQueueName =
+ "com.seafile.seafile-client.findersync.ClientCommandQueue";
+static const NSArray *const kBadgetIdentifiers = @[
+ // According to the document
+ // https://developer.apple.com/library/mac/documentation/FinderSync/Reference/FIFinderSyncController_Class/#//apple_ref/occ/instm/FIFinderSyncController/setBadgeIdentifier:forURL:
+ // Setting the identifier to an empty string (@"") removes the badge.
+ @"", // none
+ @"syncing", // syncing
+ @"error", // error
+ @"", // ignored
+ @"synced", // synced
+ @"paused", // readonly
+ @"paused", // paused
+ @"locked", // locked
+ @"locked_by_me", // locked by me
+];
+
+// Set up images for our badge identifiers. For demonstration purposes,
+static void initializeBadgeImages() {
+ // Set up images for our badge identifiers. For demonstration purposes,
+ // NONE,
+ // @""
+ // SYNCING,
+ [[FIFinderSyncController defaultController]
+ setBadgeImage:[NSImage imageNamed:@"status-syncing.icns"]
+ label:NSLocalizedString(@"Syncing", @"Status Syncing")
+ forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_SYNCING]];
+ // ERROR,
+ [[FIFinderSyncController defaultController]
+ setBadgeImage:[NSImage imageNamed:@"status-error.icns"]
+ label:NSLocalizedString(@"Error", @"Status Erorr")
+ forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_ERROR]];
+ // SYNCED,
+ [[FIFinderSyncController defaultController]
+ setBadgeImage:[NSImage imageNamed:@"status-done.icns"]
+ label:NSLocalizedString(@"Finished", @"Status Finished")
+ forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_SYNCED]];
+ // PAUSED,
+ [[FIFinderSyncController defaultController]
+ setBadgeImage:[NSImage imageNamed:@"status-ignored.icns"]
+ label:NSLocalizedString(@"Paused", @"Status Paused")
+ forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_PAUSED]];
+ // LOCKED,
+ [[FIFinderSyncController defaultController]
+ setBadgeImage:[NSImage imageNamed:@"status-locked.icns"]
+ label:NSLocalizedString(@"Locked", @"Status Locked")
+ forBadgeIdentifier:kBadgetIdentifiers[PathStatus::SYNC_STATUS_LOCKED]];
+ // LOCKED_BY_ME,
+ [[FIFinderSyncController defaultController]
+ setBadgeImage:[NSImage imageNamed:@"status-locked-by-me.icns"]
+ label:NSLocalizedString(@"Locked", @"Status LockedByMe")
+ forBadgeIdentifier:kBadgetIdentifiers
+ [PathStatus::SYNC_STATUS_LOCKED_BY_ME]];
+}
+
+inline static void setBadgeIdentifierFor(NSURL *url, PathStatus status) {
+ [[FIFinderSyncController defaultController]
+ setBadgeIdentifier:kBadgetIdentifiers[status]
+ forURL:url];
+}
+
+inline static void setBadgeIdentifierFor(const std::string &path,
+ PathStatus status) {
+ bool isDirectory = path.back() == '/';
+ std::string file = path;
+ if (isDirectory)
+ file.resize(file.size() - 1);
+ setBadgeIdentifierFor(
+ [NSURL fileURLWithPath:[NSString stringWithUTF8String:file.c_str()]
+ isDirectory:isDirectory],
+ status);
+}
+
+inline static bool isUnderFolderDirectly(const std::string &path,
+ const std::string &dir) {
+ if (strncmp(dir.data(), path.data(), dir.size()) != 0) {
+ return false;
+ }
+ const char *pos = path.data() + dir.size();
+ const char *end = pos + path.size() - (dir.size());
+ if (end == pos)
+ return true;
+ // remove the trailing "/" in the end
+ if (*(end - 1) == '/')
+ --end;
+ while (pos != end)
+ if (*pos++ == '/')
+ return false;
+ return true;
+}
+
+inline static std::vector<LocalRepo>::const_iterator
+findRepo(const std::vector<LocalRepo> &repos, const std::string &repo_id) {
+ auto pos = repos.begin();
+ for (; pos != repos.end(); ++pos) {
+ if (repo_id == pos->repo_id)
+ break;
+ }
+ return pos;
+}
+
+inline static std::string getRelativePath(const std::string &path,
+ const std::string &prefix) {
+
+ std::string relative_path;
+ // remove the trailing "/" in the header
+ if (path.size() != prefix.size()) {
+ relative_path = std::string(path.data() + prefix.size() + 1,
+ path.size() - prefix.size() - 1);
+ }
+ return relative_path;
+}
+
+inline static bool isContainsPrefix(const std::string &path,
+ const std::string &prefix) {
+ if (prefix.size() > path.size())
+ return false;
+ if (0 != strncmp(prefix.data(), path.data(), prefix.size()))
+ return false;
+ if (prefix.size() < path.size() && path[prefix.size()] != '/')
+ return false;
+ return true;
+}
+
+inline static std::vector<LocalRepo>::const_iterator
+findRepoContainPath(const std::vector<LocalRepo> &repos,
+ const std::string &path) {
+ for (auto repo = repos.begin(); repo != repos.end(); ++repo) {
+ if (isContainsPrefix(path, repo->worktree))
+ return repo;
+ }
+ return repos.end();
+}
+
+inline static void cleanEntireDirectoryStatus(
+ std::unordered_map<std::string, PathStatus> *file_status,
+ const std::string &dir) {
+ for (auto file = file_status->begin(); file != file_status->end();) {
+ auto pos = file++;
+ if (!isContainsPrefix(pos->first, dir))
+ continue;
+ setBadgeIdentifierFor(pos->first, PathStatus::SYNC_STATUS_NONE);
+ file_status->erase(pos);
+ }
+}
+
+inline static void
+cleanDirectoryStatus(std::unordered_map<std::string, PathStatus> *file_status,
+ const std::string &dir) {
+ for (auto file = file_status->begin(); file != file_status->end();) {
+ auto pos = file++;
+ if (!isUnderFolderDirectly(pos->first, dir))
+ continue;
+ file_status->erase(pos);
+ }
+}
+
+static void
+cleanFileStatus(std::unordered_map<std::string, PathStatus> *file_status,
+ const std::vector<LocalRepo> &watch_set,
+ const std::vector<LocalRepo> &new_watch_set) {
+ for (const auto &repo : watch_set) {
+ bool found = false;
+ for (const auto &new_repo : new_watch_set) {
+ if (repo == new_repo) {
+ found = true;
+ break;
+ }
+ }
+ // cleanup old
+ if (!found) {
+ // clean up root
+ setBadgeIdentifierFor(repo.worktree, PathStatus::SYNC_STATUS_NONE);
+
+ // clean up leafs
+ cleanEntireDirectoryStatus(file_status, repo.worktree);
+ }
+ }
+ for (const auto &new_repo : new_watch_set) {
+ bool found = false;
+ for (const auto &repo : watch_set) {
+ if (repo == new_repo) {
+ found = true;
+ break;
+ }
+ }
+ // add new if necessary
+ if (!found)
+ file_status->emplace(new_repo.worktree + "/",
+ PathStatus::SYNC_STATUS_NONE);
+ }
+}
+
+static std::vector<LocalRepo> watched_repos_;
+static std::unordered_map<std::string, PathStatus> file_status_;
+static FinderSyncClient *client_ = nullptr;
+static constexpr double kGetWatchSetInterval = 5.0; // seconds
+static constexpr double kGetFileStatusInterval = 2.0; // seconds
+
+@implementation FinderSync
+
+- (instancetype)init {
+ self = [super init];
+
+#ifdef NDEBUG
+ NSLog(@"%s launched from %@ ; compiled at %s", __PRETTY_FUNCTION__,
+ [[NSBundle mainBundle] bundlePath], __DATE__);
+#else
+ NSLog(@"%s launched from %@ ; compiled at %s %s", __PRETTY_FUNCTION__,
+ [[NSBundle mainBundle] bundlePath], __TIME__, __DATE__);
+#endif
+
+ // Set up client queue
+ self.client_command_queue_ =
+ dispatch_queue_create(kClientCommandQueueName, DISPATCH_QUEUE_SERIAL);
+ // Set up client
+ client_ = new FinderSyncClient(self);
+ self.update_watch_set_timer_ =
+ [NSTimer scheduledTimerWithTimeInterval:kGetWatchSetInterval
+ target:self
+ selector:@selector(requestUpdateWatchSet)
+ userInfo:nil
+ repeats:YES];
+
+ self.update_file_status_timer_ = [NSTimer
+ scheduledTimerWithTimeInterval:kGetFileStatusInterval
+ target:self
+ selector:@selector(requestUpdateFileStatus)
+ userInfo:nil
+ repeats:YES];
+
+ [FIFinderSyncController defaultController].directoryURLs = nil;
+
+ return self;
+}
+
+- (void)dealloc {
+ delete client_;
+ self.client_command_queue_ = nil;
+}
+
+#pragma mark - Primary Finder Sync protocol methods
+
+- (void)beginObservingDirectoryAtURL:(NSURL *)url {
+ // convert NFD to NFC
+ std::string absolute_path =
+ url.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+ // find where we have it
+ auto repo = findRepoContainPath(watched_repos_, absolute_path);
+ if (repo == watched_repos_.end())
+ return;
+
+ if (absolute_path.back() != '/')
+ absolute_path += "/";
+
+ file_status_.emplace(absolute_path, PathStatus::SYNC_STATUS_NONE);
+}
+
+- (void)endObservingDirectoryAtURL:(NSURL *)url {
+ // convert NFD to NFC
+ std::string absolute_path =
+ url.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+ if (absolute_path.back() != '/')
+ absolute_path += "/";
+
+ cleanDirectoryStatus(&file_status_, absolute_path);
+}
+
+- (void)requestBadgeIdentifierForURL:(NSURL *)url {
+ // convert NFD to NFC
+ std::string file_path =
+ url.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+ // find where we have it
+ auto repo = findRepoContainPath(watched_repos_, file_path);
+ if (repo == watched_repos_.end())
+ return;
+
+ NSNumber *isDirectory;
+ if ([url getResourceValue:&isDirectory
+ forKey:NSURLIsDirectoryKey
+ error:nil] &&
+ [isDirectory boolValue]) {
+ file_path += "/";
+ }
+
+ std::string repo_id = repo->repo_id;
+ std::string relative_path = getRelativePath(file_path, repo->worktree);
+ if (relative_path.empty())
+ return;
+
+ file_status_.emplace(file_path, PathStatus::SYNC_STATUS_NONE);
+ setBadgeIdentifierFor(file_path, PathStatus::SYNC_STATUS_NONE);
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doGetFileStatus(repo_id.c_str(), relative_path.c_str());
+ });
+}
+
+#pragma mark - Menu and toolbar item support
+
+#if 0
+- (NSString *)toolbarItemName {
+ return @"Seafile FinderSync";
+}
+
+- (NSString *)toolbarItemToolTip {
+ return @"Seafile FinderSync: Click the toolbar item for a menu.";
+}
+
+- (NSImage *)toolbarItemImage {
+ return [NSImage imageNamed:NSImageNameFolder];
+}
+#endif
+
+- (NSMenu *)menuForMenuKind:(FIMenuKind)whichMenu {
+ if (whichMenu != FIMenuKindContextualMenuForItems &&
+ whichMenu != FIMenuKindContextualMenuForContainer)
+ return nil;
+
+ // Produce a menu for the extension.
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
+ NSMenuItem *shareLinkItem =
+ [menu addItemWithTitle:NSLocalizedString(@"Get Seafile Download Link",
+ @"Get Seafile Download Link")
+ action:@selector(shareLinkAction:)
+ keyEquivalent:@""];
+ NSImage *seafileImage = [NSImage imageNamed:@"seafile.icns"];
+ [shareLinkItem setImage:seafileImage];
+
+ NSArray *items =
+ [[FIFinderSyncController defaultController] selectedItemURLs];
+ if (![items count])
+ return nil;
+ NSURL *item = items.firstObject;
+ std::string file_path =
+ item.path.precomposedStringWithCanonicalMapping.UTF8String;
+
+ auto repo = findRepoContainPath(watched_repos_, file_path);
+ if (repo != watched_repos_.end() && repo->internal_link_supported) {
+ NSMenuItem *internalLinkItem =
+ [menu addItemWithTitle:NSLocalizedString(@"Get Seafile Internal Link",
+ @"Get Seafile Internal Link")
+ action:@selector(internalLinkAction:)
+ keyEquivalent:@""];
+ [internalLinkItem setImage:seafileImage];
+ }
+
+ // add a menu item for lockFile
+
+ NSNumber *isDirectory;
+ bool is_dir = [item getResourceValue:&isDirectory
+ forKey:NSURLIsDirectoryKey
+ error:nil] &&
+ [isDirectory boolValue];
+
+ // we don't have a lock-file menuitem for folders
+ // early return
+ if (is_dir) {
+ NSMenuItem *showUploadLinkByMenuItem =
+ [menu addItemWithTitle:NSLocalizedString(@"Get Seafile Upload Link",
+ @"Get Seafile Upload Link")
+ action:@selector(getUploadLinkAction:)
+ keyEquivalent:@""];
+ [showUploadLinkByMenuItem setImage:seafileImage];
+ return menu;
+ }
+
+ // find where we have it
+ auto file = file_status_.find(is_dir ? file_path + "/" : file_path);
+ bool shouldShowLockedByMenu = false;
+ if (file != file_status_.end()) {
+ NSString *lockFileTitle;
+ switch (file->second) {
+ case PathStatus::SYNC_STATUS_READONLY:
+ break;
+ case PathStatus::SYNC_STATUS_LOCKED_BY_ME:
+ lockFileTitle =
+ NSLocalizedString(@"Unlock This File", @"Unlock This File");
+ break;
+ case PathStatus::SYNC_STATUS_LOCKED:
+ shouldShowLockedByMenu = true;
+ break;
+ default:
+ lockFileTitle = NSLocalizedString(@"Lock This File", @"Lock This File");
+ }
+ if (lockFileTitle) {
+ NSMenuItem *lockFileItem = [menu addItemWithTitle:lockFileTitle
+ action:@selector(lockFileAction:)
+ keyEquivalent:@""];
+
+ [lockFileItem setImage:seafileImage];
+ }
+ }
+
+ if (shouldShowLockedByMenu) {
+ NSMenuItem *showLockedByMenuItem =
+ [menu addItemWithTitle:NSLocalizedString(@"Locked by ...",
+ @"Locked by ...")
+ action:@selector(showLockedByAction:)
+ keyEquivalent:@""];
+ [showLockedByMenuItem setImage:seafileImage];
+ }
+
+ // NSString *showHistoryTitle;
+ NSMenuItem *showHistoryItem =
+ [menu addItemWithTitle:NSLocalizedString(@"View File History",
+ @"View File History")
+ action:@selector(showHistoryAction:)
+ keyEquivalent:@""];
+ [showHistoryItem setImage:seafileImage];
+
+ return menu;
+}
+
+- (IBAction)shareLinkAction:(id)sender {
+ NSArray *items =
+ [[FIFinderSyncController defaultController] selectedItemURLs];
+ if (![items count])
+ return;
+ NSURL *item = items.firstObject;
+
+ // do it in another thread
+ std::string path =
+ item.path.precomposedStringWithCanonicalMapping.UTF8String;
+ NSNumber *isDirectory;
+ if ([item getResourceValue:&isDirectory
+ forKey:NSURLIsDirectoryKey
+ error:nil] &&
+ [isDirectory boolValue])
+ path += "/";
+
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doSendCommandWithPath(FinderSyncClient::DoShareLink,
+ path.c_str());
+ });
+}
+
+- (IBAction)internalLinkAction:(id)sender {
+ NSArray *items =
+ [[FIFinderSyncController defaultController] selectedItemURLs];
+ if (![items count])
+ return;
+ NSURL *item = items.firstObject;
+
+ // do it in another thread
+ std::string path =
+ item.path.precomposedStringWithCanonicalMapping.UTF8String;
+ NSNumber *isDirectory;
+ if ([item getResourceValue:&isDirectory
+ forKey:NSURLIsDirectoryKey
+ error:nil] &&
+ [isDirectory boolValue])
+ path += "/";
+
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doSendCommandWithPath(FinderSyncClient::DoInternalLink,
+ path.c_str());
+ });
+}
+
+- (IBAction)lockFileAction:(id)sender {
+ NSArray *items =
+ [[FIFinderSyncController defaultController] selectedItemURLs];
+ if (![items count])
+ return;
+ NSURL *item = items.firstObject;
+
+ std::string path =
+ item.path.precomposedStringWithCanonicalMapping.UTF8String;
+ // find where we have it
+ auto file = file_status_.find(path);
+ if (file == file_status_.end())
+ return;
+ if (file->second == PathStatus::SYNC_STATUS_LOCKED)
+ return;
+
+ FinderSyncClient::CommandType command;
+ if (file->second == PathStatus::SYNC_STATUS_LOCKED_BY_ME)
+ command = FinderSyncClient::DoUnlockFile;
+ else
+ command = FinderSyncClient::DoLockFile;
+
+ // we cannot lock a directory
+ NSNumber *isDirectory;
+ if ([item getResourceValue:&isDirectory
+ forKey:NSURLIsDirectoryKey
+ error:nil] &&
+ [isDirectory boolValue])
+ return;
+
+ // do it in another thread
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doSendCommandWithPath(command, path.c_str());
+ });
+}
+
+- (IBAction)showHistoryAction:(id)sender {
+ NSArray *items =
+ [[FIFinderSyncController defaultController] selectedItemURLs];
+ if (![items count])
+ return;
+ NSURL *item = items.firstObject;
+
+ // do it in another thread
+ std::string path =
+ item.path.precomposedStringWithCanonicalMapping.UTF8String;
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doSendCommandWithPath(FinderSyncClient::DoShowFileHistory,
+ path.c_str());
+ });
+}
+
+
+- (void)requestUpdateWatchSet {
+ // do it in another thread
+ dispatch_async(self.client_command_queue_, ^{
+ client_->getWatchSet();
+ });
+}
+
+- (void)updateWatchSet:(void *)ptr_to_new_watched_repos {
+ std::vector<LocalRepo> new_watched_repos;
+ if (ptr_to_new_watched_repos)
+ new_watched_repos = std::move(
+ *static_cast<std::vector<LocalRepo> *>(ptr_to_new_watched_repos));
+
+ cleanFileStatus(&file_status_, watched_repos_, new_watched_repos);
+
+ // overwrite the old watch set
+ watched_repos_ = std::move(new_watched_repos);
+
+ // update FIFinderSyncController's directory URLs
+ NSMutableArray *array =
+ [NSMutableArray arrayWithCapacity:watched_repos_.size()];
+ for (const LocalRepo &repo : watched_repos_) {
+ NSString *path = [NSString stringWithUTF8String:repo.worktree.c_str()];
+ [array addObject:[NSURL fileURLWithPath:path isDirectory:YES]];
+ }
+
+ [FIFinderSyncController defaultController].directoryURLs =
+ [NSSet setWithArray:array];
+
+ // initialize the badge images
+ static bool initialized = false;
+ if (!initialized) {
+ initialized = true;
+ initializeBadgeImages();
+ }
+}
+
+- (void)requestUpdateFileStatus {
+ for (const auto &pair : file_status_) {
+ auto repo = findRepoContainPath(watched_repos_, pair.first);
+ if (repo == watched_repos_.end()) /* erase it ?*/
+ continue;
+
+ std::string relative_path = getRelativePath(pair.first, repo->worktree);
+ if (relative_path.empty())
+ relative_path = "/";
+ std::string repo_id = repo->repo_id;
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doGetFileStatus(repo_id.c_str(), relative_path.c_str());
+ });
+ }
+}
+
+- (void)updateFileStatus:(const char *)repo_id
+ path:(const char *)path
+ status:(uint32_t)status {
+ auto repo = findRepo(watched_repos_, repo_id);
+ if (repo == watched_repos_.end())
+ return;
+
+ std::string absolute_path =
+ repo->worktree + (*path == '/' ? "" : "/") + path;
+
+ // if the path is erased, ignore it!
+ auto file = file_status_.find(absolute_path);
+ if (file == file_status_.end())
+ return;
+
+ // always set up, avoid some bugs
+ file->second = static_cast<PathStatus>(status);
+ setBadgeIdentifierFor(absolute_path, static_cast<PathStatus>(status));
+}
+
+- (IBAction)showLockedByAction:(id)sender {
+ NSArray *items =
+ [[FIFinderSyncController defaultController] selectedItemURLs];
+ if (![items count])
+ return;
+ NSURL *item = items.firstObject;
+
+ // do it in another thread
+ std::string path =
+ item.path.precomposedStringWithCanonicalMapping.UTF8String;
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doSendCommandWithPath(FinderSyncClient::DoShowFileLockedBy,
+ path.c_str());
+ });
+}
+
+- (IBAction)getUploadLinkAction:(id)sender {
+ NSArray *items =
+ [[FIFinderSyncController defaultController] selectedItemURLs];
+ if (![items count])
+ return;
+ NSURL *item = items.firstObject;
+
+ // do it in another thread
+ std::string path =
+ item.path.precomposedStringWithCanonicalMapping.UTF8String;
+ dispatch_async(self.client_command_queue_, ^{
+ client_->doSendCommandWithPath(FinderSyncClient::DoGetUploadLink,
+ path.c_str());
+ });
+}
+
+@end
--- /dev/null
+//
+// FinderSyncClient.h
+// seafile-client-fsplugin
+//
+// Created by Chilledheart on 1/10/15.
+// Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#include <thread>
+#include <mutex>
+
+#include <vector>
+#include <string>
+#include "FinderSync.h"
+
+enum PathStatus : uint32_t {
+ SYNC_STATUS_NONE = 0,
+ SYNC_STATUS_SYNCING,
+ SYNC_STATUS_ERROR,
+ SYNC_STATUS_IGNORED,
+ SYNC_STATUS_SYNCED,
+ SYNC_STATUS_READONLY,
+ SYNC_STATUS_PAUSED,
+ SYNC_STATUS_LOCKED,
+ SYNC_STATUS_LOCKED_BY_ME,
+ MAX_SYNC_STATUS,
+};
+
+struct LocalRepo {
+ LocalRepo() = default;
+ LocalRepo(const LocalRepo &) = delete;
+ LocalRepo &operator=(const LocalRepo &) = delete;
+
+ LocalRepo(LocalRepo &&) = default;
+ LocalRepo &operator=(LocalRepo &&) = default;
+ enum SyncState : uint8_t {
+ SYNC_STATE_DISABLED = 0,
+ SYNC_STATE_WAITING = 1,
+ SYNC_STATE_INIT = 2,
+ SYNC_STATE_ING = 3,
+ SYNC_STATE_DONE = 4,
+ SYNC_STATE_ERROR = 5,
+ SYNC_STATE_UNKNOWN = 6,
+ SYNC_STATE_UNSET = 7,
+ MAX_SYNC_STATE,
+ };
+ LocalRepo(std::string &&r, std::string &&w, SyncState s, bool _internal_link_supported)
+ : repo_id(std::move(r)), worktree(std::move(w)), status(s), internal_link_supported(_internal_link_supported) {}
+ LocalRepo(const std::string &r, const std::string &w, SyncState s, bool _internal_link_supported)
+ : repo_id(r), worktree(w), status(s), internal_link_supported(_internal_link_supported) {}
+ std::string repo_id;
+ std::string worktree;
+ SyncState status;
+ bool internal_link_supported;
+ friend bool operator==(const LocalRepo &lhs, const LocalRepo &rhs) {
+ return lhs.repo_id == rhs.repo_id;
+ }
+ friend bool operator!=(const LocalRepo &lhs, const LocalRepo &rhs) {
+ return !(lhs == rhs);
+ }
+};
+
+class FinderSyncClient {
+ public:
+ enum CommandType : uint32_t {
+ GetWatchSet = 0,
+ DoShareLink = 1,
+ DoGetFileStatus = 2,
+ DoInternalLink = 3,
+ DoLockFile = 4,
+ DoUnlockFile = 5,
+ DoShowFileHistory = 6,
+ DoShowFileLockedBy = 7,
+ DoGetUploadLink = 8,
+ };
+
+ FinderSyncClient(FinderSync *parent);
+ ~FinderSyncClient();
+ void getWatchSet();
+ void doSendCommandWithPath(CommandType command, const char *fileName);
+ void doGetFileStatus(const char *repo, const char *fileName);
+
+ private:
+ bool connect();
+ void connectionBecomeInvalid();
+ FinderSync __weak *parent_;
+ mach_port_t local_port_;
+ mach_port_t remote_port_;
+};
--- /dev/null
+//
+// FinderSyncClient.m
+// seafile-client-fsplugin
+//
+// Created by Chilledheart on 1/10/15.
+// Copyright (c) 2015 Haiwen. All rights reserved.
+//
+
+#import "FinderSyncClient.h"
+#include <cstdint>
+#include <sstream>
+#include <iostream>
+#include <string>
+#include <servers/bootstrap.h>
+#include "../src/utils/stl.h"
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+static NSString *const kFinderSyncMachPort =
+ @"com.seafile.seafile-client.findersync.machport";
+
+static constexpr int kPathMaxSize = 1024;
+static constexpr uint32_t kFinderSyncProtocolVersion = 0x00000004;
+static volatile int32_t message_id_ =
+ 100; // we start from 100, the number below than 100 is reserved
+
+typedef std::vector<std::string> stringlist;
+
+stringlist split_string(const std::string& v, char delim) {
+ using namespace std;
+ stringlist strings;
+ istringstream ss(v);
+ string s;
+ while (getline(ss, s, delim)) {
+ strings.push_back(s);
+ }
+ return strings;
+}
+
+//
+// MachPort Message
+// - mach_msg_header_t command
+// - uint32_t version
+// - uint32_t command
+// - body
+// - mach_msg_trailer_t trailer (for rcv only)
+//
+//
+
+// buffer
+// <-char[36]-><----- char? ------------>1 1 1
+// <-repo_id--><---- [worktree name] --->0<[status]>0
+static std::vector<LocalRepo> *deserializeWatchSet(const char *buffer,
+ uint32_t size) {
+ std::vector<LocalRepo> *repos = new std::vector<LocalRepo>();
+ const char *const end = buffer + size - 1;
+ const char *pos;
+ while (buffer != end) {
+ unsigned worktree_size;
+ uint8_t status;
+ const char *repo_id = buffer;
+ buffer += 36;
+ pos = buffer;
+
+ while (*pos != '\0' && pos != end)
+ ++pos;
+ worktree_size = pos - buffer;
+ pos += 2;
+ if (pos > end || *pos != '\0')
+ break;
+
+ status = *(pos - 1);
+ if (status >= LocalRepo::MAX_SYNC_STATE) {
+ status = LocalRepo::SYNC_STATE_UNSET;
+ }
+ bool internal_link_supported = false;
+ std::string worktree = std::string(buffer, worktree_size);
+ // NSLog(@"full line = %s", worktree.c_str());
+ stringlist parts = split_string(worktree, '\t');
+ if (parts.size() > 1) {
+ worktree = parts[0];
+ // NSLog(@"worktree = %s", worktree.c_str());
+ internal_link_supported = parts[1] == "internal-link-supported";
+ }
+
+ repos->emplace_back(std::string(repo_id, 36),
+ worktree,
+ static_cast<LocalRepo::SyncState>(status),
+ internal_link_supported);
+ buffer = ++pos;
+ }
+ return repos;
+}
+
+struct mach_msg_command_send_t {
+ mach_msg_header_t header;
+ uint32_t version;
+ uint32_t command;
+ // used only in DoShareLink
+ char repo[36];
+ char body[kPathMaxSize];
+};
+
+struct mach_msg_file_status_rcv_t {
+ mach_msg_header_t header;
+ uint32_t version;
+ uint32_t command;
+ uint32_t status;
+ mach_msg_trailer_t trailer;
+};
+
+FinderSyncClient::FinderSyncClient(FinderSync *parent)
+ : parent_(parent), local_port_(MACH_PORT_NULL),
+ remote_port_(MACH_PORT_NULL) {}
+
+FinderSyncClient::~FinderSyncClient() {
+ if (local_port_) {
+ mach_port_mod_refs(mach_task_self(), local_port_,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ }
+ if (remote_port_) {
+ NSLog(@"disconnecting from Seafile Client");
+ mach_port_deallocate(mach_task_self(), remote_port_);
+ }
+}
+
+void FinderSyncClient::connectionBecomeInvalid() {
+ /* clean up old connection stage! */
+ if (local_port_) {
+ mach_port_mod_refs(mach_task_self(), local_port_,
+ MACH_PORT_RIGHT_RECEIVE, -1);
+ local_port_ = MACH_PORT_NULL;
+ }
+ if (remote_port_) {
+ NSLog(@"lost connection with Seafile Client");
+ mach_port_deallocate(mach_task_self(), remote_port_);
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [parent_ updateWatchSet:nil];
+ });
+ remote_port_ = MACH_PORT_NULL;
+ }
+}
+
+bool FinderSyncClient::connect() {
+ if (!local_port_) {
+ // Create a local port.
+ kern_return_t kr = mach_port_allocate(
+ mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &local_port_);
+ if (kr != KERN_SUCCESS) {
+ NSLog(@"unable to create connection");
+ return false;
+ }
+ }
+
+ if (!remote_port_) {
+ // connect to the mach_port
+ kern_return_t kr = bootstrap_look_up(
+ bootstrap_port,
+ [kFinderSyncMachPort cStringUsingEncoding:NSASCIIStringEncoding],
+ &remote_port_);
+
+ if (kr != KERN_SUCCESS) {
+ return false;
+ }
+ NSLog(@"connected to Seafile Client");
+ }
+
+ return true;
+}
+
+void FinderSyncClient::getWatchSet() {
+ if ([NSThread isMainThread]) {
+ NSLog(@"%s isn't supported to be called from main thread",
+ __PRETTY_FUNCTION__);
+ return;
+ }
+ if (!connect())
+ return;
+ mach_msg_command_send_t msg;
+ const int32_t recv_msgh_id = OSAtomicAdd32(2, &message_id_) - 1;
+ bzero(&msg, sizeof(mach_msg_header_t));
+ msg.header.msgh_id = recv_msgh_id - 1;
+ msg.header.msgh_local_port = local_port_;
+ msg.header.msgh_remote_port = remote_port_;
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ msg.version = kFinderSyncProtocolVersion;
+ msg.command = GetWatchSet;
+ // send a message and wait for the reply
+ kern_return_t kr = mach_msg(&msg.header, /* header*/
+ MACH_SEND_MSG | MACH_SEND_TIMEOUT, /*option*/
+ sizeof(msg), /*send size*/
+ 0, /*receive size*/
+ local_port_, /*receive port*/
+ 100, /*timeout, in milliseconds*/
+ MACH_PORT_NULL); /*no notification*/
+ if (kr != MACH_MSG_SUCCESS) {
+ if (kr == MACH_SEND_INVALID_DEST) {
+ connectionBecomeInvalid();
+ return;
+ }
+ NSLog(@"failed to send request to Seafile Client");
+ NSLog(@"mach error %s", mach_error_string(kr));
+ connectionBecomeInvalid();
+ return;
+ }
+ mach_msg_destroy(&msg.header);
+
+ utils::BufferArray recv_msg;
+ recv_msg.resize(4096);
+ mach_msg_header_t *recv_msg_header =
+ reinterpret_cast<mach_msg_header_t *>(recv_msg.data());
+ bzero(recv_msg.data(), sizeof(mach_msg_header_t));
+ recv_msg_header->msgh_local_port = local_port_;
+ recv_msg_header->msgh_remote_port = remote_port_;
+ // recv_msg.header.msgh_size = sizeof(recv_msg);
+ // receive the reply
+ kr = mach_msg(recv_msg_header, /* header*/
+ MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_LARGE, /*option*/
+ 0, /*send size*/
+ recv_msg.size(), /*receive size*/
+ local_port_, /*receive port*/
+ 100, /*timeout, in milliseconds*/
+ MACH_PORT_NULL); /*no notification*/
+ // retry
+ if (kr == MACH_RCV_TOO_LARGE) {
+ recv_msg.resize(recv_msg_header->msgh_size +
+ sizeof(mach_msg_trailer_t));
+ recv_msg_header =
+ reinterpret_cast<mach_msg_header_t *>(recv_msg.data());
+
+ kr = mach_msg(recv_msg_header, /* header*/
+ MACH_RCV_MSG | MACH_RCV_TIMEOUT, /*option*/
+ 0, /*send size*/
+ recv_msg.size(), /*receive size*/
+ local_port_, /*receive port*/
+ 100, /*timeout, in milliseconds*/
+ MACH_PORT_NULL); /*no notification*/
+ }
+ if (kr != MACH_MSG_SUCCESS) {
+ NSLog(@"failed to receive Seafile Client's reply");
+ NSLog(@"mach error %s", mach_error_string(kr));
+ connectionBecomeInvalid();
+ return;
+ }
+ if (recv_msg_header->msgh_id != recv_msgh_id) {
+ NSLog(@"mach error unmatched message id %d, expected %d",
+ recv_msg_header->msgh_id, recv_msgh_id);
+ connectionBecomeInvalid();
+ return;
+ }
+ const char *body = recv_msg.data() + sizeof(mach_msg_header_t);
+ uint32_t body_size =
+ (recv_msg_header->msgh_size - sizeof(mach_msg_header_t));
+ std::vector<LocalRepo> *repos = deserializeWatchSet(body, body_size);
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [parent_ updateWatchSet:repos];
+ delete repos;
+ });
+ mach_msg_destroy(recv_msg_header);
+}
+
+void FinderSyncClient::doSendCommandWithPath(CommandType command,
+ const char *fileName) {
+ if ([NSThread isMainThread]) {
+ NSLog(@"%s isn't supported to be called from main thread",
+ __PRETTY_FUNCTION__);
+ return;
+ }
+ if (!connect())
+ return;
+ mach_msg_command_send_t msg;
+ bzero(&msg, sizeof(msg));
+ msg.header.msgh_id = OSAtomicIncrement32(&message_id_) - 1;
+ msg.header.msgh_local_port = MACH_PORT_NULL;
+ msg.header.msgh_remote_port = remote_port_;
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+ strncpy(msg.body, fileName, kPathMaxSize);
+ msg.version = kFinderSyncProtocolVersion;
+ msg.command = command;
+ // send a message only
+ kern_return_t kr = mach_msg_send(&msg.header);
+ if (kr != MACH_MSG_SUCCESS) {
+ if (kr == MACH_SEND_INVALID_DEST) {
+ connectionBecomeInvalid();
+ return;
+ }
+ NSLog(@"failed to send sharing link request for %s", fileName);
+ NSLog(@"mach error %s from msg id %d", mach_error_string(kr),
+ msg.header.msgh_id);
+ connectionBecomeInvalid();
+ return;
+ }
+ mach_msg_destroy(&msg.header);
+}
+
+void FinderSyncClient::doGetFileStatus(const char *repo, const char *fileName) {
+ if ([NSThread isMainThread]) {
+ NSLog(@"%s isn't supported to be called from main thread",
+ __PRETTY_FUNCTION__);
+ return;
+ }
+ if (!connect())
+ return;
+ mach_msg_command_send_t msg;
+ const int32_t recv_msgh_id = OSAtomicAdd32(2, &message_id_) - 1;
+ bzero(&msg, sizeof(mach_msg_header_t));
+ msg.header.msgh_id = recv_msgh_id - 1;
+ msg.header.msgh_local_port = local_port_;
+ msg.header.msgh_remote_port = remote_port_;
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ strncpy(msg.repo, repo, 36);
+ strncpy(msg.body, fileName, kPathMaxSize);
+ msg.version = kFinderSyncProtocolVersion;
+ msg.command = DoGetFileStatus;
+ // send a message and wait for the reply
+ kern_return_t kr = mach_msg(&msg.header, /* header*/
+ MACH_SEND_MSG | MACH_SEND_TIMEOUT, /*option*/
+ sizeof(msg), /*send size*/
+ 0, /*receive size*/
+ local_port_, /*receive port*/
+ 100, /*timeout, in milliseconds*/
+ MACH_PORT_NULL); /*no notification*/
+ if (kr != MACH_MSG_SUCCESS) {
+ if (kr == MACH_SEND_INVALID_DEST) {
+ connectionBecomeInvalid();
+ return;
+ }
+ NSLog(@"failed to send request to Seafile Client");
+ NSLog(@"mach error %s", mach_error_string(kr));
+ connectionBecomeInvalid();
+ return;
+ }
+ mach_msg_destroy(&msg.header);
+
+ mach_msg_file_status_rcv_t recv_msg;
+ mach_msg_header_t *recv_msg_header =
+ reinterpret_cast<mach_msg_header_t *>(&recv_msg);
+ bzero(&recv_msg, sizeof(mach_msg_header_t));
+ recv_msg_header->msgh_local_port = local_port_;
+ recv_msg_header->msgh_remote_port = remote_port_;
+ // recv_msg.header.msgh_size = sizeof(recv_msg);
+ // receive the reply
+ kr = mach_msg(recv_msg_header, /* header*/
+ MACH_RCV_MSG | MACH_RCV_TIMEOUT, /*option*/
+ 0, /*send size*/
+ sizeof(mach_msg_file_status_rcv_t), /*receive size*/
+ local_port_, /*receive port*/
+ 100, /*timeout, in milliseconds*/
+ MACH_PORT_NULL); /*no notification*/
+ if (kr != MACH_MSG_SUCCESS) {
+ NSLog(@"failed to receive Seafile Client's reply");
+ NSLog(@"mach error %s", mach_error_string(kr));
+ connectionBecomeInvalid();
+ return;
+ }
+ if (recv_msg_header->msgh_id != recv_msgh_id) {
+ NSLog(@"mach error unmatched message id %d, expected %d",
+ recv_msg_header->msgh_id, recv_msgh_id);
+ connectionBecomeInvalid();
+ return;
+ }
+ uint32_t status = recv_msg.status;
+ if (status >= PathStatus::MAX_SYNC_STATUS)
+ status = PathStatus::SYNC_STATUS_NONE;
+
+ // copy to heap before starting block
+ std::string repo_id = repo;
+ std::string path = fileName;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [parent_ updateFileStatus:repo_id.c_str()
+ path:path.c_str()
+ status:status];
+ });
+ mach_msg_destroy(recv_msg_header);
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>Seafile FinderSync</string>
+ <key>CFBundleExecutable</key>
+ <string>Seafile FinderSync</string>
+ <key>CFBundleIconFile</key>
+ <string>seafile</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.seafile.seafile-client.findersync</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>Seafile FinderSync</string>
+ <key>CFBundlePackageType</key>
+ <string>XPC!</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.10</string>
+ <key>LSUIElement</key>
+ <true/>
+ <key>NSExtension</key>
+ <dict>
+ <key>NSExtensionAttributes</key>
+ <dict/>
+ <key>NSExtensionPointIdentifier</key>
+ <string>com.apple.FinderSync</string>
+ <key>NSExtensionPrincipalClass</key>
+ <string>FinderSync</string>
+ </dict>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2015 海文互知. All rights reserved.</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
--- /dev/null
+#!/bin/bash
+
+set -x
+set -e
+
+CURRENT_PWD="$(dirname "${BASH_SOURCE[0]}")"
+
+if [ "$(uname -s)" != "Darwin" ]; then
+ echo "don't run it if you are not using Mac OS X"
+ exit -1
+fi
+
+export CC=$(xcrun -f clang)
+export CXX=$(xcrun -f clang)
+unset CFLAGS CXXFLAGS LDFLAGS
+
+pushd $CURRENT_PWD
+CONFIG=Debug
+if [ a"$1" != "adebug" ]; then
+ rm -rf CMakeCache.txt CMakeFiles
+ CONFIG=Release
+fi
+cmake -GXcode -DCMAKE_BUILD_TYPE="$CONFIG"
+xcodebuild clean
+xcodebuild -jobs "$(sysctl -n hw.ncpu)" -configuration "$CONFIG"
+popd
+
--- /dev/null
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="779px" height="211px" version="1.1" content="<mxfile userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36" version="6.7.8" editor="www.draw.io" type="google"><diagram id="b4ffe93b-e81e-3163-fac6-cc86925c5d9a" name="Page-1">3Zhdb9owFIZ/DdJ20SqO88Ul0LJOaqVqTFp3aZJD4s3EkWMK9NfPThySNJC2WoFuQQL7tZ34POccx2aAJ8vNF0Gy5I5HwAa2FW0G+Gpg28PAVt9a2JaC43mlEAsalRKqhRl9AiNaRl3RCPJWR8k5kzRriyFPUwhlSyNC8HW724Kz9lMzEkNHmIWEddUfNJJJqQa2V+s3QOOkejLyhmXLklSdjSV5QiK+bkj4eoAngnNZlpabCTDNruJSjpseaN1NTEAqXzMAOwuA0LIcP5g7AQ4vkLHhkbCVsdbMVG4r89cJlTDLSKjra+XhAR4ncslUDaliRPIEIlNZUMYmnHFRDMWRC0HkKD2Xgv+GRktgz7EKAzw2zwchYXPQKrRjpWIM+BKk2KouZoDjBOUQE1/IM7jXtbewY7Sk4aldhBETIfHu3jVEVTAc9zN1QhcvfKSiPIwC33IuUIcgRCqeTJULmfCYp4Rd1+pY8FUaFRStNl3YUPnQKP/UXS5dXUvVRB/MiKJSt/0CKbcmkchKciXVz73lPDN3zCURcqRTRAkhI3lOw0qeUlZNojRIW9HvIWU0X4kQDgWba5KXiBhkb0R2fS2AEUkf2zP4G78dnN6RcmHh6s++XPCK631yAVUh3ZMLtnesXOgyRR2mU6oiXbyV7HugeZmMfzow9svBFqtVITtouHnbkXnV3Xrzuum2182dpc11096DBNnHQNJ9FZWhMtum4S3NJaRHCpsDzulya3BBlnfpNS4fnQqT34PphufyvIg2/Xg+BMGgQ/BbFk4Y1dZ+BHg2wpe4cTn4A8FD+PwL186ynoXL3rfhOw4SpycjTxpW+HXUmnF0uuV92ENJ6Z+mX+v65/MCOw8g1F3ZZ0DULhKUOJ3ds1VMU01KrPRPUc5JGs35pstLcZBtRAJy+mSSTh8ZMk5TWczfHQ/cK6Xok0JeHhr0AMJonKoyg4W+lYZL1aF4ZGSpTxHjXLmEpvH34khx4bzTTs19tlUL9kTucN9e7Sh+6b4var+MsoxBN7//afwufhn/seh3TtPdffIdCZN7dZz9v6Bj/9lm3H/l8eTt0FW1/supaGv8b4ev/wA=</diagram></mxfile>"><defs/><g transform="translate(0.5,0.5)"><rect x="438" y="0" width="340" height="210" fill="#d5e8d4" stroke="#82b366" stroke-dasharray="3 3" pointer-events="none"/><path d="M 366.37 105 L 431.63 105" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 361.12 105 L 368.12 101.5 L 366.37 105 L 368.12 108.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><path d="M 436.88 105 L 429.88 108.5 L 431.63 105 L 429.88 101.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/><rect x="100" y="0" width="260" height="210" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="none"/><rect x="0" y="0" width="70" height="210" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(17.5,98.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="34" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 36px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Finder</div></div></foreignObject><text x="17" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Finder</text></switch></g><rect x="448" y="50" width="106.67" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(448.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="104" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 104px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSyncListener</div></div></foreignObject><text x="52" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSyncListener</text></switch></g><rect x="554.67" y="50" width="106.67" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(565.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="85" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 87px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSyncHost</div></div></foreignObject><text x="43" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSyncHost</text></switch></g><rect x="661.33" y="50" width="106.67" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(687.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="53" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 53px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">RpcClient</div></div></foreignObject><text x="27" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">RpcClient</text></switch></g><rect x="230" y="50" width="120" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(243.5,103.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="92" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 92px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSyncClient</div></div></foreignObject><text x="46" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSyncClient</text></switch></g><rect x="110" y="50" width="120" height="120" fill="#ffffff" stroke="#000000" pointer-events="none"/><g transform="translate(111.5,96.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="116" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 116px; white-space: normal; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">FinderSync (FIFinderSync)</div></div></foreignObject><text x="58" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">FinderSync (FIFinderSync)</text></switch></g><g transform="translate(141.5,22.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="179" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Seafile FSPlugin (run in sandbox)</div></div></foreignObject><text x="90" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Seafile FSPlugin (run in sandbox)</text></switch></g><g transform="translate(521.5,22.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="74" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Seafile Applet</div></div></foreignObject><text x="37" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">Seafile Applet</text></switch></g><g transform="translate(369.5,112.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="51" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; white-space: nowrap;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">MachPort</div></div></foreignObject><text x="26" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">MachPort</text></switch></g></g></svg>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.app-sandbox</key>
+ <true/>
+ <key>com.apple.security.files.user-selected.read-only</key>
+ <true/>
+ <key>com.apple.security.application-groups</key>
+ <array>
+ <string>com.seafile.seafile-client.findersync</string>
+ </array>
+</dict>
+</plist>
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="bg_BG" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>close</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>delete</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ca" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>No s'ha pogut accedir a la base de dades</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Autorització expirada, si us plau torni a iniciar sessió</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Configuració del compte</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Si us plau indiqui l'adreça del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no és una adreça de servidor vàlida</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>No s'ha pogut guardar la informació del compte</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>No s'han pogut guardar els canvis: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>La informació del compte actual s'ha actualitzat correctament
+</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diàleg</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Adreça del servidor</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·lar</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>No s'ha pogut desincronitzar les biblioteques d'aquest compte: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>clic per obrir la pàgina web</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>versió pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Sense compte</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Triar</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Configuració del compte</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar sessió</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Esborrar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Afegir un compte</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Tancar sessió</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>no està autenticat</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Tasques de descarrega </translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>Elimina les tasques finalitzades</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>No hi ha cap descarrega</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Buida</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Tanca</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Llibreria</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Cancel·la la tasca</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>cancel·la la tasca</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Elimina la tasca </translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>No s'ha pogut cancel·lar la tasca:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>No s'ha pogut eliminar la tasca:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimitza</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Tanca</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>velocitat de descarrega</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>velocitat de pujada</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Seleccioneu el directori a sincronitzar</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>no hi ha cap servidor connectat</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>tots els servidors estan connectats</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>alguns servidors no estan connectats</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulari</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logotip</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimitza</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>tanca</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Seleccioneu</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>o arrossega el directori a sincronitzar</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>velocitat de descarrega</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>estreny </translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>velocitat de pujada</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>eixample</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>No s'ha pogut crear la configuració del ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>No s'ha pogut llegir %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Crea una llibreria</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Seleccioneu un directori</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Creant...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Seleccioneu el directori a sincronitzar</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>El directori %1 no existeix</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Introduïu el nom</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Introduïu la contrasenya</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Les contrasenyes no coincideixen</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconegut</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>No s'ha pogut descarregar:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Ruta:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Selecciona</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nom:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>encriptat</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contrasenya:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Repetiu la contrasenya:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>text d'estat</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·la</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Introduïu la contrasenya</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sincronitza la llibreria "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>No s'ha pogut descarregar:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Descarrega la llibreria</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>seleccioneu...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>La contrasenya d'aquesta llibreria:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·la</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·lar</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 inicialitzat</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Seleccioneu un directori</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>La inicialització no ha finalitzat. Esteu segur que voleu sortir?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>El directori %1 no existeix</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logotip</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Seleccioneu...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Següent</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·la</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Verificant la llibreria per defecte...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Creant la llibreria per defecte...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>No s'ha pogut crear la llibreria per defecte:
+
+Cal un servidor versió 2.1 o superior.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Descarregant la llibreria per defecte...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>La llibreria per defecte s'ha descarregat.
+Podeu clicar "Obre" per visualitzar-la.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>S'ha produït un error al descarregar la llibreria: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>No s'ha pogut descarregar la llibreria:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Omet</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Executa en segon pla</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Obre</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Acaba</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Descarrega la llibreria per defecte</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logotip</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Afegeix un compte</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Iniciant sessió...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Error de xarxa:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Atenció:</b> El certificat SSL d'aquest servidor no és de confiança, voleu continuar?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Introduïu la direcció del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no és una direcció de servidor vàlida</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Introduïu un nom d'usuari</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Introduïu la contrasenya</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>El correu electrònic o la contrasenya són incorrectes</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Error intern del servidor</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>No s'ha pogut iniciar sessió: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>No s'ha pogut iniciar sessió</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logotip</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contrasenya:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>text d'estat</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Inicia sessió</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·la</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Afegir un compte</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Refresca</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diàleg</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>sincronitzat</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexant els fitxers</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicialitzant la sincronització</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>descarregant</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>pujant</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>Mesclant </translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>Esperant per sincronitzar</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>el servidor no està connectat</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>autentificant al servidor</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>la sincronització automàtica està desactivada</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconegut</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicialitzant...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>connectant al servidor...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexant els fitxers...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Creant el directori...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Mesclant els canvis...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Finalitzat</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Cancelant</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Cancel·lat</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Llibreria "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Aquesta llibreria encara no s'ha descarregat</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Error:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Icona</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Nom</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Propietari:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Última modificació:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>mida:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Ruta local:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Estat:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Repo-Estat</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nom:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Tanca</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Aquesta llibreria no s'ha descarregat</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Actualitzat recenment</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Llibreries personals</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sub-Llibreries</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactiva la sincronització automàtica</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activa la sincronització automàtica</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Sincronitza aquesta llibreria</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancel·la la descarrega</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Cancel·la la descarrega d'aquesta llibreria</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Obre un directori</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>obre un directori local</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Desincronitza</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Deixa de sincronitzar aquesta llibreria</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Mostra a la web</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>mostra aquesta llibreria a seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>No s'ha pogut sincronitzar la llibreria "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>No s'ha pogut cancel·lar la tasca:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>S'ha cancel·lat la descarrega</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·lar</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconegut</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactiva la sincronització automàtica</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activa la sincronització automàtica</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Sortir</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Mostra la finestra</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Configuració</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Sobre</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Mostra informació sobre l'aplicació</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Ajuda a la web</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>La sincronització automàtica està desactivada</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>alguns servidors no estan connectats</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Estat de la connexió remota</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>connectat</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>desconnectat</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Tanca</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diàleg</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·lar</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Configuració</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Oculta la finestra principal al iniciar</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Notifica quan les llibreries estan sincronitzades</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Límit de baixada (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Límit de pujada (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancel·la</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>D'acord</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diàleg</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Desinstal·la %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Voleu eliminar la informació del compte %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Eliminant informació del compte...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>text</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sí</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="cs_CZ" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>O aplikaci %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Klient %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>O aplikaci</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Zkontrolovat aktualizace</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>Nepodařilo se otevřít databázi účtů</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Přihlášení vypršelo, přihlašte se prosím</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Nepodařilo se odstranit token synchronizace lokálního úložiště: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Nepodařilo se získat informace o synchronizaci ze server: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Nastavení účtu</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Napište, prosím, adresu serveru</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 není platná adresa serveru</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Nelze uložit informace o účtu</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Nelze uložit změny: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Informace o účtu byly úspěšně změněny</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Adresa serveru</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>Opravdu chceš smazat účet %1?<br><br>Účet bude lokálně odstraněn. Budou také odstraněna veškerá nastavení synchronizace. Účet na serveru nebude ovlivněn.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Nepodařilo se odebrat synchronizaci knihoven tohoto účtu: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>Otevřít v prohlížeči</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>pro verze</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Žádný účet</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Vybrat</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Nastavení účtu</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Přihlásit</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Smazat</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Přidat účet</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Odhlásit</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>nepřihlášeno</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulář</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Účet</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>server</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Aktivita souborů je podporována pouze v %1 Server Professional Edition</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>opakovat</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Nepodařilo se získat informace o aktivitách. Prosím% 1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Nahrávání úspěšné</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Soubor "%1"
+nahrán úspěšně.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Soubor "%1"
+nahrání selhalo.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Chyba oprávnění!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Přihlášení vypršelo</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Soubor neexistuje</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>Soubor je uzamčen uživatelem %1, zkus to prosím znovu poději</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Chyba nahrávání: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Chyba při vytváření složky profilových fotografií</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Kontroluji oprávnění</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Stahování</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>odstranit všechny úspěšné úkoly</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Neprobíhá žádné stahování</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Vyčistit</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavřít</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Knihovna</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Cesta</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Zrušit tuto úlohu</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>zrušit tuto úlohu</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Odebrat tuto úlohu</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Nemohu zrušit tuto úlohu:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Nemohu odebrat tuto úlohu:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimalizovat</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavřít</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Knihovny</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Oblíbené</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Aktivity</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Hledat</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>aktuální rychlost stahování</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>aktuální rychlost uploadu</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Vyberte adresář k synchronizaci</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>není připojen žádný server</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>všechny servery jsou připojeny</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>některé servery nebyly připojeny</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulář</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimalizovat</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>zavřít</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Vybrat</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>značka</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>nebo přetáhnout složku k synchronizaci</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>rychlost stahování</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>šipka dolů</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>rychlost uploadu</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>šipka nahoru</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Chyba při vytváření ccnet konfigurace</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Nepodařilo se vytvořit předkonfigurační adresář "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>chyba při čtení %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Vytvořit knihovnu</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Vyberte adresář</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Vytvářím...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Nepodařilo se vygenerovat šifrovací klíč pro knihovnu</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Vyberte adresář k synchronizaci</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Adresář %1 neexistuje</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Vložte jméno</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vložte heslo</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Hesla se neshodují</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Neznámá chyba</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Nelze přidat stahování:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Nelze vytvořit knihovnu na serveru:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Cesta:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Vybrat</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Název:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>šifrováno</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Heslo:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Heslo znovu:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>stavový text</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 klient se nepodařilo spustit</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 byl neočekávaně ukončen</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vložte heslo</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Synchronizovat knihovnu %1</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Synchronizovat složku "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Synchronizovat do složky</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>nebo</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>Synchronizovat existující adresář</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>Vytvořit nový synchronizační adresář</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Synchronizovat tento existující adresář</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Prosím zvolte složku</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Složka neexistuje</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Prosím zvolte složku k dynchronizaci</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Vaše organizace znemožnila umístění knihovny mimo adresář %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Dochází ke konfliktu se souborem "%1", prosím zvolte jinou složku.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Dochází ke konfliktu s knihovnou "%1", prosím zvolte jinou složku.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Složka "%1" již existuje.Jste si jistí že s ní chcete synchronizovat (obsah bude sloučen)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Klikněte Ne pro synchronizaci s novou složkou</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Nepodařilo se najít alternativní název adresáře</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Nelze přidat stahování:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Nepodařilo se stáhnout informace o repozitáři:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Stáhnout knihovnu</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>vybrat...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Heslo pro tuto knihovnu:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Podrobnosti o změnách</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Přidané soubory</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Smazané soubory</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Změněné soubory</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Přidané složky</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Smazané složky</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Otevřít</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Otevřít & rodičovská složka</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Prohlížeč souborů v Cloudu</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Zpět</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Vpřed</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Domů</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Nahrát soubory</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Nahrát adresář</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Nemáte oprávnění pro nahrání souborů do této knihovny</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Vytvořit adresář</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Obnovit</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 položek</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Jméno adresáře</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Neplatné jméno adresáře!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Jméno "%1" uz existuje.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>opakovat</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Chyba při stahování informací o souborech<br/>
+Prosím %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Složka je prázdná</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Vložte název souboru, do kterého si přejete uložit...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Nelze odstranit soubor "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Vložte cestu ke knihovně, do které si přejete ukládat...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Přejete si přepsat existující soubor "%1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Soubor "%1" nebyl synchronizován</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Soubor %1 již existuje.<br/>Chcete ho přepsat?<br/><small>(Zvolte Ne pokud ho chcete nahrát s jiným názvem).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Soubor neexistuje</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Selhalo stažení souboru: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Vyberte soubor k nahrání</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Vybrat adresář k nahrání</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Přejmenovat</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Opravdu chcete smazat tyto položky</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Vytváření adresáře selhalo</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Uzamčení souboru selhalo</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Vybrat soubor pro aktualizaci %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Přejmenování selhalo</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Odstranění selhalo</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Sdílení selhalo</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Nelze vložit soubory z toho samého adresáře</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>Nelze vložit složku</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kopírování selhalo</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Přesun selhal</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Vytvoření knihovny selhalo</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Nemáte práva nahrát tuto složku</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Přihlášení vypršelo</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Chyba oprávnění!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Knihovna/složka nenalezena.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Nepodařilo se nahrát soubor %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>Nepodařilo se vytvořit složku mezipaměti</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>Nepodařilo se otevřít složku mezipaměti</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Vyhledat soubory</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Nepodařilo se získat odkaz</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>Nepodařilo se získat odkaz pro nahrání souboru "%1" ze serveru</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>Čekající</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Nahrát</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Nahrávám %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Stáhnout</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Stahuji %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 z %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Selhalo nahrání souboru: %1, opakovat?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Opakovat</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Přeskočit</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Přerušit</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Ukládám</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Uložení souboru selhalo</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Název</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Velikost</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Poslední úprava</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Zobrazit ve složce</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Zobrazit ve složce</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operace zrušena</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>čekající</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>úloha zrušena</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Vnitřní chyba serveru</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Kvóta na severu je obsazená</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>uzamčeno %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Název</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Velikost</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Poslední úprava</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Uložit jako...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Zamknout</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Přejmenovat</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Smazat</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Sdílet se skupinou</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Aktualizovat</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Kopírovat</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Vyjmou&t</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Vložit</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Zrušit stahování</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Synchronizovat tento adresář</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Tato funkcionalita je dostupná pouze v PRO verzi
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Vygenerovat odkaz ke stažení</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Sdílet s uživatelem</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>Vygenerovat %1 interní odkaz</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Uložit jako do...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Odemknout</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>S oprávněním ke čtení není možno odstranit soubory </translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Nelze vyjmout soubory pouze pro čtení</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Opakovat upload</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Smazat místní verzi</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Selhalo vytváření adresářů</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Selhalo vytváření dočasných souborů</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Selhalo zapsání souboru na disk</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Selhalo odstranění starší verze stahovaného souboru</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Selhalo přesunutí souboru</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 inicializace</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Vyberte adresář %1</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Vyberte adresář</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inicializace není kompletní. Opravdu ukončit?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Adresář %1 neexistuje</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Vyberte adresář</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Prosím vyberte adresář. V něm vytvoříme podadresář %1. Až stáhnete knihovnu, uloží se zde.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Vybrat...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Další</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Kontrola výchozí knihovny ...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Vytvářím výchozí knihovnu...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Nepodařilo se vytvoření základní knihovny:
+
+Verze serveru musí být 2.1 nebo vyšší.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Nepodařilo se získat výchozí knihovnu:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Nepodařilo se vytvořit výchozí knihovnu:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Stahuji výchozí knihovnu...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Nelze stáhnout výchozí knihovnu:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Výchozí knihovna byla stažena.
+Klikněte na tlačítko "Otevřít" pro zobrazení.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Chyba při stahování výchozí knihovny:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Nelze stáhnout výchozí knihovnu:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Přeskočit</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Spustit na pozadí</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Otevřít</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Dokončit</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Stáhnout výchozí knihovnu:</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ano</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>nahrát další</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Nahrání log souborů selhalo</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Nahrát log soubory</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Chyba oprávnění!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Knihovna/složka nenalezena.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Přihlášení vypršelo</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Nahrání log souborů selhalo :%1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Úspěšně byly nahrány log soubory</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Komprimuji</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Přidat účet</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Single Sign On - SSO</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Znovu přihlásit</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Přihlašuji se...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Chyba sítě:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Varování:</b> SSL certifikát serveru není důvěryhodný, přesto pokračovat?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Vložte adresu serveru</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 není platná adresa serveru</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Vaše uživatelské jméno</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Název počítače</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 adresa serveru</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>Adresa serveru nesmí být prázdná</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vložte heslo</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Nesprávný email nebo heslo</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Přihlašujete se příliš často, prosím počkejte chvíli</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Vnitřní chyba serveru</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Chyba při přihlášení: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Chyba při přihlášení</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Server:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Například: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>nebo http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Heslo:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>stavový text</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Název počítače:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Uživ. jméno:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>například Honzův počitač</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Login</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Automatické přihlášení</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Jste odhlášen. Prosím</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>Login</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Přidat účet</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Obnovit</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Sdílet %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Vložte název skupiny</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Vložte uživatelské jméno nebo emailovou adresu</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Úspěšně aktualizováno</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>Operace sdílení selhala: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Úspěšně odstraněno</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Nepodařilo se stáhnout informace pro sdílení adresáře</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Nepodařilo se stáhnout informace o skupinách a kontaktech</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Prosím zadejte uživatelské jméno</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Prosím zadejte název skupiny</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Skupina "%1" neexistuje</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Se skupinou %1 je již sdíleno</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>S uživatelem %1 je již sdíleno</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Stále probíhá předchozí operace</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Sdílet s:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Sdílet</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Oprávnění</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Číst a zapisovat</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Pouze číst</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavřít</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>synchronizováno</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexuji soubory</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Synchronizace zhájena</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>stahuji</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>Nahrávám</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>synchronizace spojení</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>čekám na synchronizaci</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>sever není připojen</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>autentizace serveru</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>automatická synchronizace je vypnuta</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>neznámý/á</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Neznámá chyba</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Chyba připojení</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Nemohu se připojit k serveru</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Chyba při navazování zabezpečeného připojení. Zkontrolujte SSL certifikát serveru</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Chyba serveru</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Nedostatek paměti</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Limit úložiště vyčerpán</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Knihovna je smazána na serveru</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Knihovna je poškozena na serveru</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Kvóta na severu je obsazená</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Inicializuji...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>připojuji server...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexuji soubory...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Stahuji seznam souborů...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Stahuji soubory...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Vytvářím adresář...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Sloučit změny souborů ...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Hotovo</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>kontroluji informace ze serveru...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Rušení</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Zrušeno</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Chyba SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Chyba sítě: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Chyba serveru</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>Chyba při otevírání databáze certifikátů</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Soubor "%1" v "%2" neexistuje</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 nelze najít aplikaci, která otevře soubor %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Vytvořena knihovna "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Smazána knihovna "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Přejmenovat %1 na</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Není možné stáhnout "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>kopírování selhalo</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Přidáno</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Smazáno</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Odebráno</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Upraveno</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Přejmenováno</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Přidáno nebo upraveno</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Přemístěno</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Přidán adresář</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Odebraný adresář</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Přejmenovaný adresář</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Přesunutý adresář</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>soubory</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>adresáře</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>a %1 dalších</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Stav knihovny navrácen k</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Stav souboru "%1" byl navrácen k "%2"</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Smazaný adresář byl obnoven</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Název nebo popis knihovny byl změněn</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Automatické spojení systémem %1</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Právě teď</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>Včera</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>před %1 dny</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>před 1 hodinou</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>před %1 hodinami</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>před minutou</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>před %1 minutami</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Synchronizovat tuto knihovnu s:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Synchronizovat tento adresář s:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Složka</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Dokument pouze ke čtení</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Dokument</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF Dokument</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Obrázek</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Dokument</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Zvuk</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Video soubor</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word Dokument</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint Dokument</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel Dokument</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Cesta "%1" koliduje se systémovou cestou</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Cesta "%1" koliduje s existující knihovnou</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>nahrávám seznam souborů</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>Soubor je uzamčen jinou aplikací</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>Složka je uzamčena jinou aplikací</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>Soubor je uzamčen jiným uživatelem</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Nesprávná cesta</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Chyba indexace</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>Cesta končí mezerou nebo znakem tečky</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>Cesta obsahuje nepovolený znak jako '|' nebo ':'</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>Nepovedlo se otevřít databázi dočasných souborů</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>Knihovna obsahuje nepovolené znaky, jako třeba ':', '*', '|', '?'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>Aktualizace souboru odmítnuta nastavením oprávnění složky</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>%1 klient již běží</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>Interní data v klientovi jsou poškozená. Pokus se přesynchronizovat knihovnu prosím</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>Nemáš oprávnění zapisovat do této knihovny</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>Nemáš oprávnění synchronizovat tuto složku</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>Odstraněny všechny předměty z koše</translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>Odstraněny předměty starší než %1 dní z koše</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>Publikovaný koncept</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>Vytvořený koncept</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>Vytvořený soubor</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>Přejmenovaný soubor</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>Smazaný koncept</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>Smazaný soubor</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>Obnovený soubor</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>Přesunutý soubor</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>Aktualizovaný soubor</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>Vytvořená složka</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>Přejmenovaná složka</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>Smazaná složka</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>Obnovená složka</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>Přesunutá složka</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>Vytvořená knihovna</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>Přejmenovaná knihovna</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>Smazaná knihovna</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>Obnovená knihovna</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>Soubor byl vytvořen nebo upraven v nezapisovatelné knihovně, nebo složce</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>Oprávnění na serveru nepřiděleno</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>Souběžné aktualizace souboru. Soubor je uložen jako konfliktní</translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>Složka, která může obsahovat nedokončeně nahrané soubory byla přesunuta do složky seafile-recycle-bin.</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation>nepovedlo se otevřít id databáze chyby synchronizace</translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>Soubor neexistuje</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Knihovna "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Tato knihovna nebyla stažena</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Chyba:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>každých %1 vteřin</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>RepoIcon</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>RepoName</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>TextLabel</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Vlastník:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Poslední modifikace:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Velikost:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Místní cesta:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Status:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>RepoStatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Název:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Interval synchronizace:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavřít</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Tato knihovna nebyla stažena</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Nepodařilo se otevřít soubor "%1" v neexistující knihovně "%2"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Nedávno aktualizované</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Moje knihovny</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Podknihovny</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Sdíleno se mnou</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Sdíleno se všemi</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Sdíleno se skupinama</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Synchronizované knihovny</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>spuštění synchronizace</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Zrušit automatickou synchronizaci</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Automatická synchronizace</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Zobrazit detaily</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Zobrazit detaily knihovny</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>Synchronizovat tuto knihovnu</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Synchronizovat tuto knihovnu</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Nedávno aktualizované</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Synchronizovat</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Okamžitě synchronizovat knihovnu</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>Zrušit stahování</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Zrušit stahování této knihovny</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Otevřít adresář</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>otevřít lokální adresář</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>&Otevřít místní adresář</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Zrušit synchronizaci</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Zrušit synchronizaci této knihovny</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>Zobrazit na serveru</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>Zobrazit tuto knihovnu na serveru</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Sdílet s uživatelem</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Sdílet tuto knihovnu s uživatelem</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Sdílet se skupinou</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Sdílet tuto knihovnu se skupinou</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Otevřít prohlížeč souborů cloudu</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>Otevřít tuto knihovnu v Prohlížeči souborů Cloudu</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>&Zrušit sdílení</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>zrušit sdílení</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>Resynchronizovat knihovnu</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>Zrušit synchronizaci a znovu synchronizovat tuto knihovnu</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Nastavit synchronizaci &Interval</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>nastavit interval synchronizace pro tuto knihovnu</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>Chceš opravdu zrušit synchronizaci knihovny "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>Chceš opravdu znovu zesynchronizovat knihovnu "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>Chceš opravdu přepsat soubor "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Chyba při rušení synchronizace "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>Jsi si jistý, že chceš opustit sdílený disk "%1"?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Nepovedlo se opustit sdílený disk</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Chyba při rušení ulohy:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Stahování bylo zrušeno</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Nemáš oprávnění nahrávat do této složky</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Přepsání souboru %1 sebou samým se nezdařilo</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Nelze smazat soubor "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Nelze nahrát soubor: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Interval synchronizace (ve vteřinách):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Nastavit interval synchronizace pro knihovnu "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Prohledat knihovny</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>opakovat</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Nepodařilo se získat informace o knihovně<br/>Prosím %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Varování:</b> SSL certifikát serveru není důvěryhodný, přesto pokračovat?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Nezdařilo se spuštění logu: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ano</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ne</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>nepovedlo se uložit id klienta</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>nepovedlo se získat %1</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>nesprávné id klienta</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>nepovedlo se přečíst %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 Interní odkaz</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Zkopírovat do schránky</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>%1 Interní odkaz:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>%1 Přístupový odkaz plochy</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Neznámá chyba</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>Interní chyba: nepovedlo se spojit s démonem</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Zrušit automatickou synchronizaci</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Automatická synchronizace</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Ukončit</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Zobrazit hlavní okno</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Nastavení</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Otevřít &adresář %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>otevřít %1 adresář</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Otevřít adresář log souborů</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Zobrazit chyby synchronizace souborů</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&O aplikaci</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Zobrazit informace O aplikaci</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Online nápověda</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Soubor</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>automatická synch. je zakázana</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Nahrávání</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Stahování</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>otevřít adresář s logy %1</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>otevřít online nápovědu %1</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>některé servery nejsou připojeny</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Nahrát soubory záznamu</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>nahrát %1 souborů záznamu</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Nejdřív se prosím přihlašte</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>Opravit rozšíření Průzkumníku</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>Ikony v Průzkumníku byli úspěšně opraveny.</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>Nepovedlo se opravit ikony synchronizace v Průzkumníku</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>máš nějaké problémy se synchronizací</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Zobrazit ve složce</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Zobrazit ve složce</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Hledat soubory</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>zkusit znovu</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Hledání se nezdařilo <br /> Prosím %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Informace o serverech</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>připojeno</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>odpojeno</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavřít</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Nastavte, prosím, heslo knihovny</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Zadejte heslo pro knihovnu %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vložte heslo</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Nesprávné heslo</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Neznámá chyba</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Nastavení</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Automaticky spustit %1 po přihlášení</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Skrýt ikonu %1 ze spouštěče</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Žádný</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP Proxy</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 Proxy</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Systémová proxy</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Byla provedena změna jazyka. Restartovat pro použití?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>Adresa proxy hostitele nesmí být prázdná</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Port proxy je nesprávný</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>Uživatelské jméno proxy nesmí být prázdné</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>Uživatelské heslo proxy nesmí být prázdné</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Skrýt hlavní okno po startu</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Informovat, že knihovny byly synchromizovány</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Povolit synchronizaci pro dočasné soubory MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Download limit (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Upload limit (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Základní</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Nezrušit automaticky synchronizaci knihovny</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Nezrušit automaticky synchronizaci knihovny v případě, že je lokální adresář odstraněn nebo je nepřístupný z jiných důvodů</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Nezrušit synchronizaci knihovny pokud knihovna není nalezena na serveru</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Nezrušit synchronizaci knihovny pokud knihovna není nalezena na serveru</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Povolit rozšíření FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Povolit rozšíření Průzkumníku souborů</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Automaticky kontrolovat aktualizace</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Neověřovat certifikát při HTTPS synchronizaci</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Povolit synchronizaci s existujícím adresářem pod jiným názvem</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Rozšířené</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Jazyk (vyžaduje restart)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Jazyk</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Typ proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Host:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Uživatelské jméno</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Heslo:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Proxy server vyžaduje heslo</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Síť</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Číst a zapisovat</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Pouze číst</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Zrušit sdílení</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Klikni pro úpravu</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Vytvořeno %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Číst a zapisovat</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Pouze číst</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Skupina</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Uživatel</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Oprávnění</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Předchozí operace stále probíhá</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Sdílet odkaz</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Sdílet odkaz:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Přímé stažení</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Zkopírovat do schránky</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation>Odkaz pro nahrání:</translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation>Odkaz pro nahrání:</translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Nezabezpečené spojení</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 používá neplatný zabezpečovací certifikát. Spojení může být nezabezpečené. Opravdu chcete pokračovat?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Aktuální otisk RSA klíče je %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Předchozí otisk RSA klíče byl %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Zapamatovat výběr</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ano</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ne</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>& Otevřít</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Otevřít soubor</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>zobrazit v prohlížeči</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>otevřít tento soubor v prohlížeči</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>opakovat</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Chyba při stahování informací o oblíbených souborech<br> Prosím %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Nemáte žádné oblíbené soubory.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Chyba synchronizace souborů</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Žádné chyby synchronizace.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Dvakrát klikni pro otevření knihovny</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Knihovna</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Cesta</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Chyba</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Čas</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Zadej druhý dvoufaktorový token</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Dvoufaktorové ověření</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Zadej prosím token pro dvoufaktorové ověření</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Zapamatovat si toto zařízení</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušit</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Odinstalovat %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Opravdu chcete odebrat informace o účtu %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Odebírám informace o účtu...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>text</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ano</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ne</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="de_DE" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Über %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Client %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Über</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Auf Aktualisierungen prüfen</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>Fehler beim Aufruf der Datenbank</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Legitimierung abgelaufen, bitte erneut anmelden</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Entfernen des lokalen Tokens zum Synchronisieren nicht möglich: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Abrufen der Informationen zum Synchronisieren nicht möglich: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Kontoeinstellungen</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Bitte geben Sie die Serveradresse ein</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 ist keine gültige Serveradresse. Haben Sie „http(s)://“ vorangestellt?</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Die Kontoinformationen konnten nicht gespeichert werden</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Die Änderungen konnten nicht gespeichert werden: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Die Kontoinformationen wurden aktualisiert</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Serveradresse</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-Mail</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>Möchten Sie das Konto %1 entfernen?<br /><br />Das Konto wird dann lokal entfernt. Alle Einstellungen zum Synchronisieren werden ebenfalls gelöscht. Das Konto auf dem Server wird nicht verändert.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Synchronisieren der Bibliothek von „%1“ konnte nicht aufgehoben werden</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>Zum Öffnen der Website anklicken</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>Pro Version</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Kein Konto</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Auswählen</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Kontoeinstellungen</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Anmelden</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Löschen</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Ein Konto hinzufügen</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Ausloggen</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>Nicht angemeldet</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formular</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Konto</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>E-Mail</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>Server</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation><b>Aktivitäten</b> werden nur von %1 Pro unterstützt.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>wiederholen</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Informationen zur Aktivität waren nicht abrufbar. Bitte %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Erfolgreich hochgeladen</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Datei „%1“
+erfolgreich hochgeladen.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Datei „%1“
+wurde nicht hochgeladen.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Keine ausreichenden Rechte!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Legitimierung abgelaufen</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Datei ist nicht vorhanden</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>Die Datei ist von %1 gesperrt, bitte versuchen Sie es später noch einmal</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Fehler beim Hochladen: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Avatarordner konnte nicht erstellt werden</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Rechte werden geprüft</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Download-Aufgaben</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>Alle erfolgreich erledigten Aufgaben entfernen</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Keine Download-Aufgaben eingerichtet</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Leeren</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Schließen</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Bibliothek</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Pfad</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Diese Aufgabe abbrechen</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>diese Aufgabe abbrechen</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Diese Aufgabe entfernen</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fehler beim Abbrechen dieser Aufgabe:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Fehler beim Entfernen dieser Aufgabe:
+
+ %1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimieren</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Schließen</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotheken</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favoriten</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Aktivitäten</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Suche</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>aktuelle Download-Geschwindigkeit</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>aktuelle Upload-Geschwindigkeit</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Bitte einen Ordner zum Synchronisieren auswählen</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>kein Server verbunden</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>Alle Server verbunden</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>einige Server nicht verbunden</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formular</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimieren</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>schließen</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>…</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Ordner wählen</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>oder ablegen</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>Download-Geschwindigkeit</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>Abwärtspfeil</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>Upload-Geschwindigkeit</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>Aufwärtspfeil</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Fehler beim Erstellen der ccnet-Konfiguration</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Fehler beim Erstellen des vorkonfigurierten Ordners „%1“</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>Fehler beim Lesen von %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Eine Bibliothek erstellen</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Bitte einen Ordner auswählen</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Wird erstellt …</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Fehler beim Verschlüsseln dieser Bibliothek</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Bitte wählen Sie den zu synchronisierenden Ordner</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Der Ordner %1 ist nicht vorhanden</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Bitte geben Sie den Namen ein</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Bitte geben Sie das Passwort ein</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Passwörter sind nicht identisch</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Download konnte nicht eingerichtet werden:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Fehler beim Erstellen der Bibliothek auf dem Server: %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Pfad:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Auswählen</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Name:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>verschlüsselt</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Passwort:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Passwort wiederholen:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>Status-Text</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>Fehler beim Initialisieren des %1-Clients </translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 ist unerwartet abgebrochen</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Bitte geben Sie das Passwort ein</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Bibliothek „%1“ synchronisieren</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>„%1“ wird synchronisiert</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Bibliothek in folgendem Ordner speichern und synchronisieren:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>oder</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>mit vorhandenem Ordner synchronisieren</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>einen neuen Ordner zum Synchronisieren erstellen</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Mit diesem bereits vorhandenen Ordner synchronisieren:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Bitte wählen Sie einen Ordner</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Der Ordner ist nicht vorhanden</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Bitte wählen Sie einen Ordner zum Synchronisieren</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Ihre Organisation erlaubt nicht, eine Bibliothek außerhalb des Ordners %1 abzulegen.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Konflikt mit der bereits vorhandenen Datei „%1“, bitte wählen Sie einen anderen Ordner.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Konflikt mit der bereits vorhandenen Bibliothek „%1“, bitte wählen Sie einen anderen Ordner.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Der Ordner „%1“ ist bereits vorhanden. Möchten Sie ihn wirklich synchronisieren und die Inhalte zusammenführen?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Nein klicken, um stattdessen mit einem neuen Ordner zu synchronisieren</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Es konnte kein alternativer Ordnername gefunden werden</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Download konnte nicht eingerichtet werden:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Informationen zum Herunterladen der Paketquellen waren nicht abrufbar:
+Bitte %1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Bibliothek herunterladen</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>ändern …</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Passwort für diese Bibliothek:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Bearbeitungsdetails</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Neue Dateien</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Gelöschte Dateien</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Geänderte Dateien</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Neue Ordner</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Gelöschte Ordner</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Öffnen</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>&Übergeordneten Ordner öffnen</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>%1-Dateibrowser</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Zurück</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Vorwärts</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Start</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Dateien hochladen</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Ordner hochladen</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Sie haben keine ausreichenden Rechte zum Hochladen in diese Bibliothek</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Neuer Ordner</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Aktualisieren</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 Objekte</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Name des Ordners</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Ungültiger Ordner-Name!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Der Name „%1“ wird bereits benutzt.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>wiederholen</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Informationen zu Dateien waren nicht abrufbar.<br/>Bitte %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Der Ordner ist leer.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Speichern unter …</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Fehler beim Löschen der Datei „%1“</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Geben Sie den Pfad des gewünschten Speicherorts an …</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Möchten Sie die vorhandene Datei „%1“ wirklich ersetzen?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Datei „%1“ ist nicht synchronisiert</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Die Datei %1 ist schon vorhanden.<br/>Möchten Sie die Datei wirklich überschreiben?<br/><small>(Wählen Sie Nein, um die Datei mit einem anderen Namen hochzuladen).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Datei ist nicht vorhanden</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Fehler beim Herunterladen der Datei: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Datei zum Hochladen auswählen</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Wählen Sie einen Ordner zum Hochladen aus</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Umbennenen</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Möchten Sie die ausgewählten Objekte wirklich löschen?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Fehler beim Erstellen des Ordners</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Sperren fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Datei zum Hochladen auswählen %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Umbenennen fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Entfernen fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Freigeben fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Dateien aus dem selben Ordner können nicht eingefügt werden</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>Ordner können nicht in ihre Unterordner kopiert werden</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kopieren fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Verschieben fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Das Erstellen der Bibliothek ist fehlgeschlagen!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Sie haben keine ausreichenden Rechte zum Hochladen in diesen Ordner</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Legitimierung abgelaufen</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Keine ausreichenden Rechte!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Bibliothek oder Ordner nicht gefunden</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Fehler beim Hochladen der Datei %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>Cache-Ordner konnte nicht erstellt werden</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>Cache-Ordner konnte nicht geöffnet werden</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Datei suchen</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fehler beim Ermitteln des Links</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>Informationen zum Upload-Link von Datei „%1“ konnten nicht abgerufen werden.</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>In Vorbereitung</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbruch</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Hochladen</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Hochladevorgang %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Herunterladen</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Herunterladevorgang %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 von %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Fehler beim Hochladen der Datei „%1“. Möchten Sie den Versuch wiederholen?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Wiederholen</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Überspringen</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Speichern …</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Speichern der Datei fehlgeschlagen</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>Fehler beim Indizieren des Fortschritts %1</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Name</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Größe</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Zuletzt geändert</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>Im Ordner &ansehen</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Im Ordner ansehen</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Vorgang abgebrochen</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>ausführend</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>Aufgabe abgebrochen</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Interner Serverfehler</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Speicherplatz ist verbraucht</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>Gesperrt von %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Name</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Größe</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Zuletzt geändert</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>Modifikator</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Speichern unter …</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Sperren</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Umbenennen</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Löschen</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Freigeben für Gruppe</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Aktualisieren</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Kopieren</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>&Ausschneiden</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Einfügen</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>&Herunterladen abbrechen.</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Diesen Ordner synchronisieren</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Dieses Feature ist nur in der Pro-Version verfügbar
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>%1 &Download-Link erstellen</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Freigeben für Nutzer/in</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>Internen Link erstellen</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Speichern unter …</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Ent&sperren</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Schreibgeschützte Dateien können nicht gelöscht werden</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Schreibgeschützte Dateien können nicht ausgeschnitten werden</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Hochladen wiederholen</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Lokale Version löschen</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Lokale Version speichern unter …</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Lokalen Zwischenspeicher öffnen</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation>%1 &Upload-Link erstellen</translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fehler beim Ermitteln des Links</translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation>Die Datei „%1“ ist von %2 gesperrt</translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation>Datei „%1“ ist gesperrt. Nähere Informationen konnten nicht abgerufen werden.</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation>Upload-Link von Datei „%1“ konnte nicht abgerufen werden.</translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Fehler beim Erstellen der Ordner</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Fehler beim Erstellen der temporären Dateien</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Konnte Dateien nicht auf Laufwerk schreiben</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Fehler beim Entfernen der älteren Version der heruntergeladenen Datei</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Konnte Datei nicht verschieben</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Initialisierung</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Einen %1-Ordner auswählen</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Bitte wählen Sie einen Ordner</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Initialisierung nicht abgeschlossen. Wirklich beenden?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Der Ordner %1 ist nicht vorhanden</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Ordner wählen</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Bitte wählen Sie einen Ort, an dem der Standard-Ordner von %1 erstellt werden soll. Wenn Sie künftig Bibliotheken herunterladen, ist dieser %1-Ordner als Ziel vorausgewählt.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Auswählen …</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Weiter</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organisiert Dateien in Bibliotheken.
+Möchten Sie Ihre Standardbibliothek herunterladen?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Standardbibliothek wird überprüft …</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Standardbibliothek wird erstellt …</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Fehler beim Erstellen der Standardbibliothek:
+
+Die Serverversion muss 2.1 oder höher sein, um dies zu unterstützen.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Fehler beim Herunterladen der Standardbibliothek:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Fehler beim Erstellen der Standardbibliothek:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Standardbibliothek wird heruntergeladen …</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Fehler beim Herunterladen der Standardbibliothek:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Die Standardbibliothek ist heruntergeladen.
+Klicken Sie auf „Öffnen“, um sie anzusehen.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Fehler beim Herunterladen der Standardbibliothek: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Fehler beim Herunterladen der Standardbibliothek:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organisiert Dateien in Bibliotheken.
+Möchten Sie Ihre Standardbibliothek herunterladen?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Überspringen</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Im Hintergrund laufen lassen</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Öffnen</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Abschließen</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Standardbibliothek herunterladen</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>mehr laden</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Protokolldateien konnten nicht hochgeladen werden</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Protokolldateien werden hochgeladen</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Keine ausreichenden Rechte!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Bibliothek oder Ordner nicht gefunden</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Legitimierung abgelaufen</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Protokolldateien konnten nicht hochgeladen werden: %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Protokolldateien sind hochgeladen</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Komprimieren der Daten</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 von %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Konto hinzufügen</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Single Sign-On</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Erneut anmelden</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Anmeldung wird durchgeführt …</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Netzwerkfehler:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Warnung:</b> Das SSL-Zertifikat dieses Servers ist nicht vertrauenswürdig. Trotzdem fortfahren?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Bitte geben Sie die Serveradresse ein</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 ist keine gültige Serveradresse. Haben Sie „http(s)://“ vorangestellt?</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Bitte geben Sie den Benutzernamen ein</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Bitte geben Sie den Rechnernamen ein</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1-Serveradresse</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>Bitte geben Sie die Serveradresse ein</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 ist keine gültige Serveradresse. Haben Sie „https://“ vorangestellt?</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Bitte geben Sie das Passwort ein</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>E-Mail-Adresse oder Passwort sind ungültig</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Zu viele Anmeldeversuche, bitte warten Sie eine Minute</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Interner Serverfehler</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Fehler beim Anmelden: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Fehler beim Anmelden</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Server:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Zum Beispiel: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>oder http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Passwort:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>Statustext</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Rechnername:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>E-Mail / Benutzername:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>z.B. Freyas Laptop</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Anmelden</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Automatisch anmelden</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Sie sind abgemeldet. Bitte </translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>Anmelden</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Ein Konto hinzufügen</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Ansicht aktualisieren</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>„%1“ wurde synchronisiert</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Dateien hochgeladen in „%1“</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>Datei %1 konnte nicht synchronisiert werden.
+Die Datei wird von einem anderen Programm verwendet. Die Datei wird aktualisiert, sobald Sie das Programm beenden.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>Ordner %1 konnte nicht synchronisiert werden.
+Der Ordner wird von einem anderen Programm verwendet. Der Ordner wird aktualisiert, sobald Sie das Programm beenden.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>Datei %1 konnte nicht synchronisiert werden.
+Die Datei wurde von jemand anderem gesperrt. Ihre neue Version dieser Datei kann nicht hochgeladen werden.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>Datei %1 konnte nicht indiziert werden.
+Bitte überprüfen Sie die Dateirechte und den freien Speicherplatz.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>%1 konnte nicht synchronisiert werden.
+Der Dateipfad endet mit einem Leerschritt oder Punkt und kann auf Windows nicht erstellt werden.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>%1 konnte nicht synchronisiert werden.
+Die Ordnerstruktur enthält ungültige Zeichen. Synchronisieren mit diesem Computer ist nicht möglich.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>Die Datei %1 kann wegen der Rechteeinstellungen des Ordners nicht aktualisiert werden.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>Sie haben keine ausreichenden Rechte, um den Ordner %1 zu synchronisieren.</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation>Aktualisierungen in der schreibgeschützten Bibliothek %1 werden nicht hochgeladen.</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation>Die Datei wurde parallel aktualisiert. Version %1 wurde als Konfliktdatei gespeichert </translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation>Ordner %1 wurde in den Papierkorb von Seafile verschoben, da er noch nicht hochgeladene Dateien enthält.</translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation>Der Ordner in Bibliothek %1 ist gelöscht oder verschoben. Die Bibliothek wurde nicht synchronisiert.</translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Freigeben: %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Gruppenname eingeben</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Benutzernamen oder E-Mail-Adresse eingeben</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Aktualisiert</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>Freigabe fehlgeschlagen: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Entfernt</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Informationen zur Freigabe des Ordners nicht verfügbar</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Informationen zu Ihren Gruppen und Kontakten nicht verfügbar</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Bitte geben Sie den Benutzernamen ein</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Bitte geben Sie den Gruppennamen ein</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Keine Gruppe gefunden mit Namen %1</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Bereits freigegeben für Gruppe %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Bereits freigegeben für Nutzer/in %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Der laufende Vorgang ist noch nicht abgeschlossen</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Freigeben für:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Freigeben</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Rechte:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lesen + Schreiben</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Nur Lesen</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Schließen</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>synchronisiert</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indiziere Dateien</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Synchronisieren initialisiert</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>herunterladen</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>hochladen</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>Zusammenfügen der Synchronisierung</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>auf Synchronisieren warten</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>Server nicht verbunden</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>Server-Legitimierung</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>Synchronisieren ist angehalten</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>unbekannt</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Netzwerkfehler</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>Proxy-Adresse kann nicht aufgelöst werden</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>Serveradresse kann nicht aufgelöst werden</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Kann nicht mit dem Server verbinden</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Sichere Verbindung kann nicht hergestellt werden. Bitte überprüfen Sie das SSL-Zertifikat des Servers</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>Die Datenübertragung wurde unterbrochen. Bitte überprüfen Sie das Netzwerk oder die Firewall</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Die Datenübertragung wurde abgebrochen. Bitte überprüfen Sie das Netzwerk oder die Firewall</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Der Server verwendet ein ungültiges „http redirect“. Bitte überprüfen Sie die Konfiguration des Server</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Serverfehler</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Nicht genügend Arbeitsspeicher</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>Das lokale Programm konnte keine Daten speichern. Bitte überprüfen Sie den freien Speicherplatz und die Schreibrechte in den Ordnern</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Kein Speicherplatz mehr</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Bibliothek auf dem Server ist gelöscht</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Bibliothek auf dem Server ist beschädigt</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Das Speicherkontingent wurde aufgebraucht</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Initialisierung läuft …</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>Mit Server verbinden …</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>Dateien werden indiziert …</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Dateiliste wird geladen …</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Dateien werden geladen …</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Ordner wird erstellt …</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Dateiänderungen werden zusammengefügt …</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Fertig</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>Überprüfe die Server-Informationen …</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Abgebrochen</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL-Fehler</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Netzwerkfehler: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Serverfehler</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>Fehler beim Öffnen der Zertifikatsdatenbank</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Datei „%1“ fehlt in „%2“</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 konnte keine Anwendung finden zum Öffnen von Datei %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Neue Bibliothek: %1</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Gelöschte Bibliothek „%1“</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>%1 umbenennen zu</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Fehler beim Herunterladen von „%1“</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>Fehler beim Kopieren</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Neu:</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Gelöscht:</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Entfernt</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Geändert:</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Umbenannt:</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Neu oder geändert:</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Verschoben:</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Neuer Ordner:</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Entfernter Ordner</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Umbenannter Ordner</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Verschobener Ordner</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>Dateien</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>Ordner</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>und noch %1</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Bibliothek zurückgesetzt zum Status von</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Datei „%1“ zurückgesetzt auf den Status von %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Gelöschter Ordner wiederhergestellt</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Bibliotheksname oder Beschreibung geändert</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Automatische Zusammenführung durch %1</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>gerade eben</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>vor 1 Tag</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>vor %1 Tagen</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>vor 1 Stunde</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>vor %1 Stunden</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>vor 1 Minute</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>vor %1 Minuten</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Nicht Teil des Zertifikates></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Bibliothek hier als neuen Unterordner erstellen:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Ordner hier als neuen Unterordner erstellen:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Ordner</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Schreibgeschützter Ordner</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Dokument</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF-Dokument</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Bild</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Textdokument</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Audiodatei</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Videodatei</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word-Dokument</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint-Dokument</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel-Dokument</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Der Pfad „%1“ wird bereits vom System verwendet</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Der Pfad „%1“ wird bereits von einer Bibliothek verwendet</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>Dateiliste wird hochgeladen</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>Datei wird von einer anderen Anwendung verwendet</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>Ordner wird von einer anderen Anwendung verwendet</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>Datei wird von jemand anderem verwendet</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Ungültiger Pfad</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Fehler beim Indizieren</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>Pfad endet mit einem Leerschritt oder Punkt</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>Pfad enthält ungültige Zeichen wie „|“ oder „:“</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>Fehler beim Öffnen der Datei-Cache Datenbank</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>Der Name der Bibliothek darf keine Zeichen wie „:“, „*“, „|“ oder „?“ enthalten</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>Die Datei kann wegen der Rechteeinstellungen des Ordners nicht aktualisiert werden </translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>%1 läuft bereits</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>Bitte versuchen Sie, die Bibliothek neu zu synchronisieren. Es gibt einen Fehler bei der internen Datenverwaltung des lokalen Programms.</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>Keine Schreibrechte für die Bibliothek</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>Sie haben keine ausreichenden Rechte, um diesen Ordner zu synchronisieren</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>Alle Objekte aus dem Papierkorb entfernt</translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>Objekte entfernt, die länger als %1 Tage im Papierkorb waren</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>Entwurf veröffentlicht</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>Entwurf erstellt</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>Datei erstellt</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>Datei umbenannt</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>Entwurf gelöscht</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>Datei gelöscht</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>Datei weiderhergestellt</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>Datei verschoben</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>Datei aktualisiert</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>Ordner erstellt</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>Ordner umbenannt</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>Ordner gelöscht</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>Ordner wiederhergestellt</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>Ordner verschoben</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>Bibliothek erstellt</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>Bibliothek umbenannt</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>Bibliothek gelöscht</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>Bibliothek wiederhergestellt</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>Datei hochgeladen oder erzeugt in einer Bibliothek oder einem Ordner ohne Schreibzugriff</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>Der Server hat den Zugang abgelehnt.</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>Die Datei wurde parallel aktualisiert. Sie wurde als Konfliktdatei gespeichert </translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>Ein Ordner, der noch nicht hochgeladene Dateien enthalten könnte, wurde in den Papierkorb von Seafile verschoben.</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation>Fehler beim Öffnen der Datenbank zu Problemen bei der Synchronisation</translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>Datei ist nicht vorhanden</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Bibliothek „%1“</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Diese Bibliothek wurde noch nicht heruntergeladen</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Fehler: </translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>alle %1 Sekunden</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Bibliothekssymbol</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Bibliotheksname</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>TextLabel</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Eigentümer/in:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Zuletzt geändert:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Größe:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Lokaler Pfad:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Status:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Bibliotheksstatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Name:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Sync-Intervall:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Schließen</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>nicht heruntergeladen</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Kann Datei „%1“ nicht öffnen, Bibliothek „%2“ nicht vorhanden</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Letzte Änderungen</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Meine Bibliotheken</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Unter-Bibliotheken</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Für mich freigegeben</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Für meine Abteilung</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Für meine Gruppen</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Synchronisierte Bibliotheken</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Synchronisieren vorbereiten</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Synchronisieren aussetzen</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Synchronisieren fortsetzen</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>&Details</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Details dieser Bibliothek anzeigen</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>Herunterladen und &synchronisieren</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Herunterladen und synchronisieren</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Letzte Änderungen</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>&Manuell synchronisieren</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Diese Bibliothek sofort synchronisieren</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>Herunterladen &abbrechen</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Herunterladen dieser Bibliothek abbrechen</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>Im lokalen &Ordner ansehen</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>Lokalen Ordner öffnen</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>Lokalen &Ordner öffnen</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Synchronisieren trennen</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Diese Bibliothek nicht mehr synchronisieren</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>Im Webbrowser ansehen</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>Diese Bibliothek auf Seahub ansehen</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Freigeben für Nutzer/in</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Bibliothek für Nutzer/in freigeben</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Freigeben für Gruppe</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Bibliothek für Gruppe freigeben</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>Im &%1-Dateibrowser ansehen</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>Bibliothek im %1-Dateibrowser öffnen</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>&Freigegebene Bibliothek verlassen</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>Freigegebene Bibliothek verlassen</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Neu synchronisieren</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>Synchronisieren trennen und erneut ausführen</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Sync-&Intervall festlegen</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>Sync-Intervall für diese Bibliothek festlegen</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>Soll die Bibliothek „%1“ wirklich nicht mehr synchronisiert werden?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>Möchten Sie die Bibliothek „%1“ wirklich neu synchronisieren?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>Möchten Sie die Datei „%1“ wirklich überschreiben?</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Fehler beim Trennen des Synchronisierens der Bibliothek „%1“</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>Möchten Sie „%1“ wirklich verlassen?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Die freigegebene Bibliothek konnte nicht verlassen werden</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fehler beim Abbruch dieser Aufgabe:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Das Herunterladen wurde abgebrochen</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Sie haben keine ausreichenden Rechte zum Hochladen in diesen Ordner</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Fehler beim Ersetzen der Datei „%1“</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Fehler beim Löschen der Datei „%1“</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Fehler beim Hochladen der Datei: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Sync-Intervall (in Sekunden):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Sync-Intervall für Bibliothek „%1“ festlegen</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Bibliothek suchen</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>wiederholen</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Fehler beim Ermitteln der Bibliotheksinformationen.<br/>Bitte %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Warnung:</b> Das SSL-Zertifikat dieses Servers ist nicht vertrauenswürdig. Trotzdem fortfahren?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Log konnte nicht initialisiert werden: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nein</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>Fehler beim Speichern der ID des Programms</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>Fehler beim Zugriff auf %1</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>ID des Programms ist nicht richtig</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>Fehler beim Lesen von %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1-interner Link:</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopieren</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>%1-interner Link:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>Link für den Desktop-Zugang %1:</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>Interner Fehler: Verbindung zum Daemon-Hintergrundprogramm nicht möglich</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Synchronisieren aussetzen</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Synchronisieren fortsetzen</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Beenden</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Hauptfenster</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Einstellungen</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>%1-Ordner</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>öffne %1-Ordner</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>&Protokollordner</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Synchronisierungs-Fehler anzeigen</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Über</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Den „Über“-Dialog der Anwendung anzeigen</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Onlinehilfe</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Datei</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>Synchronisieren ist angehalten</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Wird hochgeladen</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Wird heruntergeladen</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>öffne %1-Protokollordner</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>öffne %1-Onlinehilfe</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Einige Server nicht verbunden</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Protokolldaten hochladen</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>%1 Protokolldateien werden hochgeladen</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Bitte melden Sie sich zuerst an</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>Die Explorer-Erweiterung wiederherstellen</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>Icons im Explorer sind wiederhergestellt</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>Fehler beim Wiederherstellen der Icons im Explorer</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>Fehler beim Synchronisieren</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>Im lokalen &Ordner ansehen</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Im lokalen Ordner ansehen</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Datei suchen</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>Neue Suche</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Suche fehlgeschlagen<br />Bitte %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Verbindungsstatus der Server</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>verbunden</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>nicht verbunden</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Schließen</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Bitte geben Sie das Bibliothekspasswort ein</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>%1: Diese Bibliothek ist verschlüsselt. Bitte geben Sie das Passwort ein.</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Bitte geben Sie das Passwort ein</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Falsches Passwort</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Unbekannter Fehler</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Einstellungen</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>%1 nach der Anmeldung automatisch starten</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>%1-Icon aus dem Dock ausblenden</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Kein Proxy</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP-Proxy</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5-Proxy</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Proxy-Einstellungen des Systems</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Sie haben die Sprache geändert. Möchte Sie neustarten um die neue Sprache zu verwenden?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>Adresse des Proxy-Servers erforderlich</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Port des Proxy-Servers ist fehlerhaft</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>Nutzername für den Proxy-Server erforderlich</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>Passwort für den Proxy-Server erforderlich</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Hauptfenster nach dem Start ausblenden</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Benachrichtigen, wenn Bibliotheken synchronisiert sind</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Temporäre Dateien von MS Office und LibreOffice synchronisieren</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Maximale Download-Geschwindigkeit (kB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Maximale Upload-Geschwindigkeit (kB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Allgemein</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Synchronisieren einer Bibliothek trotz lokalem Fehler nicht trennen</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Das Synchronisieren einer Bibliothek nicht automatisch trennen, wenn sie lokal nicht gefunden wird, z.B. weil sie verschoben oder umbenannt wurde.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Synchronisieren einer Bibliothek trotz Server-Fehler nicht trennen</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Das Synchronisieren einer Bibliothek nicht automatisch trennen, wenn sie auf dem Server nicht gefunden wird.</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Finder-Erweiterung aktivieren</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Die Explorer-Symbole anzeigen</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Automatisch auf Aktualisierungen prüfen</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Server-Zertifikat bei https-Synchronisierung nicht überprüfen</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Synchronisieren von Ordnern mit unterschiedlichen Namen ermöglichen</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Erweitert</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Sprache (Neustart erforderlich):</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Sprache</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Proxy-Typ:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Host:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Benutzername:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Passwort:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Für den Proxy-Server ist ein Passwort erforderlich</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Netzwerk</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lesen + Schreiben</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Nur Lesen</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Freigabe beenden</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Zum Bearbeiten klicken</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Erstellt von %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lesen + Schreiben</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Nur Lesen</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Gruppe</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Nutzer/in</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Rechte</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Der laufende Vorgang ist noch nicht abgeschlossen</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Freigabe-Link</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Freigabe-Link:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Direkt-Download</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopieren</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation>Upload-Link</translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation>Upload-Link:</translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Nicht vertrauenswürdige Verbindung</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 benutzt ein nicht vertrauenswürdiges Sicherheitszertifikat. Die Verbindung ist möglicherweise nicht sicher. Trotzdem fortfahren?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Aktueller Fingerabdruck des RSA-Schlüssels ist %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Vorheriger Fingerabdruck des RSA-Schlüssels ist %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Meine Auswahl merken</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nein</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>Lokal &öffnen</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Diese Datei öffnen</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>Im &Webbrowser öffnen</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>Diese Datei auf der Website ansehen</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>wiederholen</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Informationen zu Favoriten konnten nicht geladen werden.<br/>Bitte %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Sie haben noch keine Dateien als Favoriten markiert..</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Fehler beim Synchronisieren</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Keine Fehler beim Synchronisieren.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Doppelklick zum Öffnen der Bibliothek</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Bibliothek</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Pfad</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Fehler</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Zeit</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Geben Sie das Token der 2-Faktor-Authentifizierung ein</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>2-Faktor-Authentifizierung</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Geben Sie das Token der 2-Faktor-Authentifizierung ein</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mSMS</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Dieses Gerät merken</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Abbrechen</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Deinstallieren %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Möchten Sie die Kontoinformationen für %1 wirklich entfernen?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Kontoinformationen werden entfernt …</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>Text</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nein</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="el_GR" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Περί %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 πελάτης %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Περί</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Έλεγχος για ενημερώσεις</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Εντάξει</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>αποτυχία ανοίγματος της βάσης δεδομένων του λογαριασμού</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Η πιστοποίηση έληξε, παρακαλούμε συνδεθείτε ξανά</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Ρυθμίσεις λογαριασμού</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Παρακαλούμε εισάγετε την διεύθυνση του διακομιστή</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 δεν είναι έγκυρη διεύθυνση διακομιστή</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Αποτυχία αποθήκευσης των πληροφοριών του λογαριασμού</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Αποτυχία αποθήκευσης των αλλαγών: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Η ενημέρωση των πληροφοριών του λογαριασμού εκτελέστηκε με επιτυχία</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Διεύθυνση διακομιστή</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Εντάξει</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Ακύρωση</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Αποτυχία αναίρεσης συγχρονισμού των βιβλιοθηκών του λογαριασμού:% 1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>κάντε κλικ για να ανοίξετε την ιστοσελίδα</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>έκδοση pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Κανένας λογαριασμός</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Επιλέξτε</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Ρυθμίσεις λογαριασμού</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Σύνδεση</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Διαγραφή</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Προσθήκη λογαριασμού</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Αποσύνδεση</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>δεν είστε συνδεδεμένος</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Φόρμα</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Λογαριασμός</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>διακομιστής</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Οι δραστηριότητες αρχείων υποστηρίζονται μόνο στην %1 επαγγελματική έκδοση διακομιστή.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>δοκιμάστε ξανά</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Αποτυχία λήψης των πληροφοριών δραστηριοτήτων. Παρακαλούμε% 1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Επιτυχία μεταφόρτωσης</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Το αρχείο "%1"
+μεταφορτώθηκε με επιτυχία.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Το αρχείο "%1"
+δεν μεταφορτώθηκε.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Αποτυχία δημιουργίας φακέλου avatar</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Άκυρο</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Λήψη εργασιών</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>απομάκρυνση των επιτυχημένων εργασιών</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Δεν υπάρχει λήψη εργασιών αυτή τη στιγμή.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Εκκαθάριση</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Κλείσιμο</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Βιβλιοθήκη</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Διαδρομή</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Ακύρωση της εργασίας</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>ακύρωση αυτής της εργασίας</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Αφαίρεση αυτής της εργασίας</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Αποτυχία ακύρωσης της εργασίας:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Αποτυχία αφαίρεσης της εργασίας:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Ελαχιστοποίηση</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Κλείσιμο</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Βιβλιοθήκες</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Με αστεράκι</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Δραστηριότητες</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Αναζήτηση</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>τρέχουσα ταχύτητα λήψης</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>τρέχουσα ταχύτητα μεταφόρτωσης</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Παρακαλούμε επιλέξτε ένα φάκελο για συγχρονισμό</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>κανένας συνδεδεμένος διακομιστής</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>όλοι οι διακομιστές είναι συνδεδεμένοι</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>μερικοί διακομιστές δεν είναι συνδεδεμένοι</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Φόρμα</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>λογότυπο</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>ελαχιστοποίηση</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>κλείσιμο</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Επιλέξτε</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>ή Αποθέστε φάκελο για Συγχρονισμό</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>ταχύτητα λήψης</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>κάτω βέλος</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>ταχύτητα μεταφόρτωσης</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>άνω βέλος</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Σφάλμα κατά την δημιουργία της ρυθμίσεων ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Αποτυχία δημιουργίας του προρυθμισμένου φακέλου "%1¨"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>αδυναμία ανάγνωσης %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Δημιουργία βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Παρακαλούμε επιλέξτε έναν φάκελο</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Δημιουργία...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Αποτυχία δημιουργίας κρυπτογραφημένου κλειδιού για αυτή τη βιβλιοθήκη</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Παρακαλούμε επιλέξτε τον φάκελο που θέλετε να συγχρονίσετε</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Ο φάκελος %1 δεν υπάρχει</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Παρακαλούμε εισάγετε το όνομα</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Παρακαλούμε εισάγετε το συνθηματικό</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Τα συνθηματικά δεν ταιριάζουν</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Άγνωστο σφάλμα</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Αποτυχία προσθήκης διεργασίας λήψης:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Αποτυχία δημιουργιας βιβλιοθήκης στον διακομιστή:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Διαδρομή:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Επιλέξτε</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Όνομα:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>κρυπτογραφημένο</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Συνθηματικό</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Επιβεβαίωση συνθηματικού:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>κείμενο κατάστασης</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Εντάξει</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Ακύρωση</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 αποτυχία αρχικοποίησης πελάτη</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Παρακαλούμε εισάγετε το συνθηματικό</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Συγχρονισμός της βιβλιοθήκης "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Συγχρονισμός φακέλου "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Συγχρονισμός στον φάκελο:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ή</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>συγχρονισμός με υπάρχων φάκελο</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>δημιουργία ενός νέου φακέλου συγχρονισμού</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Συγχρονισμός με αυτό τον υπάρχων φάκελο:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Παρακαλούμε επιλέξτε έναν φάκελο</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Ο φάκελος δεν υπάρχει</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Παρακαλούμε επιλέξτε τον φάκελο που θα συγχρονιστεί.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Ο οργανισμός σας έχει απενεργοποιήσει την δυνατότητα τοποθέτησης μίας βιβλιοθήκης εκτός του φακέλου %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Υπάρχει διένεξη με το υπάρχον αρχείο "%1"¨, παρακαλούμε επιλέξτε διαφορετικό φάκελο.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Υπάρχει διένεξη με την υπάρχουσα βιβλιοθήκη "%1", παρακαλούμε επιλέξτε ένα διαφορετικό φάκελο.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Ο φάκελος "%1" υπάρχει ήδη. Είστε σίγουροι πως θέλετε να τον συγχρονίσετε (τα περιεχόμενα θα συγχωνευθούν);</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Κάντε κλικ στο Όχι για να συγχρονίσετε με ένα νέο φάκελο</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Αδυναμία εύρεσης εναλλακτικού ονόματος φακέλου</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Αποτυχία προσθήκης διεργασίας λήψης:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Αποτυχία λήψης πληροφοριών λήψης repo:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Λήψη βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>επιλέξτε...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Κωδικός για αυτή τη βιβλιοθήκη:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ΟΚ</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Άκυρο</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Λεπτομέρειες τροποποίησης</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Αρχεία που προστέθηκαν</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>ΔΙεγραμμένα αρχεία</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Τροποποιημένα αρχεία</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Φάκελοι που προστέθηκαν</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Διεγραμμένοι φάκελοι</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Άνοιγμα</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Άνοιγμα &γονικού φακέλου</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Εξερευνητής αρχείων cloud</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Πίσω</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Εμπρός</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Αρχική</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Μεταφόρτωση αρχείων</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Μεταφόρτωση φακέλου</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Δεν έχετε δικαιώματα μεταφόρτωσης αρχείων σε αυτή τη βιβλιοθήκη</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Δημιουργία φακέλου</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Ανανέωση</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Όνομα φακέλου</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Μη συμβατό όνομα φακέλου</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Το όνομα "%1" χρησιμοποιείται ήδη.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>δοκιμάστε ξανά</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Αποτυχία λήψης πληροφοριών αρχείων<br/>Παρακαλώ %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Αυτός ο φάκελος είναι κενός.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Εισάγετε όνομα αρχείου για αποθήκευση</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Αποτυχία αφαίρεσης αρχείου "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Εισάγετε την διαδρομή του φακέλου στον οποίο θέλετε αν αποθηκεύσετε...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Θέλετε να αντικαθαστήσετε το υπάρχον αρχείο "%1";</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Το αρχείο "%1" δεν έχει συγχρονιστεί</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Το αρχείο %1 υπάρχει ήδη.<br/>Θέλετε να το αντικαταστήσετε;<br/><small>(Επιλέξτε Όχι για να μεταφορτώσετε το αρχείο με διαφορετικό όνομα).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Αποτυχία λήψης του αρχείου: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Επιλέξτε ένα αρχείο για μεταφόρτωση</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Επιλέξτε ένα φάκελο για μεταφόρτωση</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Μετονομασία</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Θέλετε να διαγράψετε αυτή τα τα στοιχεία</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Αποτυχία δημιουργία φακέλου</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Το κλείδωμα του αρχείου απέτυχε</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Επιλέξτε ένα αρχείο για ενημέρωση %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Αποτυχία μετονομασίας</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Αποτυχία διαγραφής</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Αποτυχία κοινής χρήσης</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Δεν μπορείτε να επικολλήσετε αρχεία από τον ίδιο φάκελο</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Αποτυχία αντιγραφής</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Αποτυχία μετακίνησης</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Αποτυχία δημιουργίας βιβλιοθήκης!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Αναζήτηση αρχείων</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Άκυρο</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Μεταφόρτωση</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Μεταφορτώνεται %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Λήψη</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Λαμβάνεται %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 από %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Όνομα</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Μέγεθος</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Τελευταία τροποποίηση</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Η διεργασία ακυρώθηκε</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>σε εξέλιξη</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Εσωτερικό σφάλμα στον διακομιστή</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>κλειδώθηκε από %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Όνομα</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Μέγεθος</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Τελευταία τροποποίηση</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Αποθήκευση ως...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Κλείδωμα</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Μετονομασία</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Διαγραφή</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Διαμοιρασμός στην ομάδα</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Ενημέρωση</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Αντιγραφή</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Αποκ&οπή</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Επικόλληση</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Ακύρω&ση λήψης</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Συγχρονισμός αυτού του φακέλου</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Αυτή η δυνατότητα είνα διαθέσιμη στην έκδοση pro
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Διαμοιρασμός στον χρήστη</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Αποθήκευση ως σε...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Ξε&κλείδωμα</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Αποτυχία αφαίρεσης αρχείων μόνο για ανάγνωση</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Αδυναμία αποκοπής αρχείων μόνο για ανάγνωση</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Αποτυχία δημιουργίας φακέλων</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Αποτυχία δημιουργίας προσωρινών αρχείων</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Αποτυχία εγγραφής του αρχείου στον δίσκο</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Αποτυχία διαγραφής παλιότερης έκδοσης του ληφθέντος αρχείου</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Αποτυχία μετακίνησης του αρχείου</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Αρχικοποίηση</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Παρακαλώ επιλέξτε ένα φάκελο</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Η ενεργοποίηση δεν έχει τελείωσει. Θέλετε σίγουρα να σταματήσετε;</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Ο φάκελος %1 δεν υπάρχει</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>λογότυπο</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Επιλογή φακέλου</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Επιλέξτε...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Επόμενο</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Άκυρο</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Έλεγχος της προεπιλεγμένης βιβλιοθήκης σας...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Δημιουργία προεπιλεγμένης βιβλιοθήκης...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Αποτυχία δημιουργίας της προεπιλεγμένης ββλιοθήκης:
+
+Η έκδοση του δισκομιστή σας πρέπει να είνια 2.1 ή ανώτερη για να υποστηρίξει αυτό..</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Αποτυχία λήψης της προεπιλεγμένης βιβλιοθήκης:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Αποτυχία δημιουργίας της προεπιλεγμένης βιβλιοθήκης:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Γίνεται λήψη της προεπιλεγμένης βιβλιοθήκης...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Αποτυχία λήψης της προεπιλεγμένης βιβλιοθήκης:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Η προεπιλεγμένη βιβλιοθήκη έχει ληφθεί.
+Μπορείτε να κάνετε κλικ στο "Άνοιγμα" για να την προβάλετε.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Σφάλμα κατά την λήψη της προεπιλεγμένης βιβλιοθήκης: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Αποτυχία λήψης της προεπιλεγμένης βιβλιοθήκης:
+ %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Παράλειψη</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Εκτέλεση στο παρασκήνιο</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Άνοιγμα</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Ολοκλήρωση</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Λήψη προεπιλεγμένης βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ναι</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>λογότυπο</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>φόρτωση περισσοτέρων</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Ακύρωση</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 από %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Προσθήκη λογαριασμού</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Επανασύνδεση</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Σύνδεση σε εξέλιξη...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Σφάλμα δικτύου:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Προσοχή:</b> Το πιστοποιητικό ssl αυτού του διακομιστή δεν είναι έμπιστο, θέλετε να συνεχίσετε;</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Παρακαλώ εισάγετε την διεύθυνση του διακομιστή</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 δεν είναι έκγυρη διεύθυνση διακομιστή</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Παρακαλώ συμπληρώστε το όνομα χρήστη</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Παρακαλώ συμπληρώστε το όνομα του υπολογιστή</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 Διεύθυνση διακομιστή</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Παρακαλώ εισάγετε τον κωδικό πρόσβασης</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Λάθος email ή κωδικός πρόσβασης</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Πολύ συχνές συνδέσεις, παρακαλώ περιμένετε ένα λεπτό</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Εσωτερικό σφάλμα διακομιστή</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Αποτυχία σύνδεσης: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Αποτυχία σύνδεσης στον λογαριασμό</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>λογότυπο</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Διακομιστής:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Για παράδειγμα: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>ή http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Κωδικός πρόσβασης:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>κείμενο κατάστασης</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Όνομα υπολογιστή:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Όνομα χρήστη:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>π.χ. Το laptop του Γιάννη</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Σύνδεση</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Άκυρο</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Αυτόματη είσοδος</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>¨Εχετε αποσυνδεθεί. Παρακαλώ</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>συνδεθείτε</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Προσθήκη λογαριασμού</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Ανανέωση</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Εισάγετε το όνομα της ομάδας</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Επιτυχημένη ενημέρωση</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Επιτυχημένη αφαίρεση</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Παρακαλούμε εισάγετε το όνομα χρήστη</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Παρακαλούμε εισάγετε το όνομα της ομάδας</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Διαμοιρασμός σε:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Διαμοιρασμός</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Δικαιώματα:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Ανάγνωση-Εγγραφή</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Μόνο ανάγνωση</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Κλείσιμο</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>συγχρονίστηκε</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>ευρετηρίαση αρχείων</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>αρχικοποίηση συγχρονισμού</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>λήψη</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>μεταφόρτωση</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>ο συγχρονισμός συγχωνεύει</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>αναμονή για συγχρονισμό</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>ο διακομιστής δεν είναι συνδεδεμένος</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>ο διακομιστής πιστοποιείται</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>ο αυτόματος συγχρονισμός είναι απενεργοποιημένος</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>άγνωστο</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Άγνωστο σφάλμα</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Σφάλμα δικτύου</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Αδυναμία σύνδεσης στον διακομιστή</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Σφάλμα διακομιστή</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Το όριο χρήσης χώρου έχει χρησιμοποιηθεί</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>αρχικοποίηση...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>σύνδεση σε εξέλιξη..</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>Δημιουργία ευρετηρίου αρχείων</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Λήψη λίστας αρχείων...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Λήψη αρχείων...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Δημιουργία φακέλου...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Συγχώνευση αλλαγών αρχείων...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Ολοκληρώθηκε</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>έλεγχος πληροφοριών διακομιστή...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Ακύρωση σε εξέλιξη</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Ακυρώθηκε</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>σφάλμα SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Σφάλμα δικτύου: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Σφάλμα διακομιστή</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>αποτυχία ανοίγματος βάσης δεδομένων πιστοποιητικών</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Το αρχείο "%1" δεν υπάρχει στο "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>το "%1" δεν μπόρεσε να βρει εφαρμογή για να ανοίξει το αρχείο %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Η βιβλιοθήκη "%1" δημιουργήθηκε</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Η βιβλιοθήκη "%1" διαγράφηκε</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Μετονομασία %1 σε</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Αποτυχία λήψης του αντικειμένου "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>η αντιγραφή απέτυχε</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Προστέθηκε</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Διαγράφτηκε</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Αφαιρέθηκε</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Τροποποιήθηκε</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Μετονομάστηκε</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Προστέθηκε ή τροποποιήθηκε</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Μετακινήθηκε</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Προσθήκη φακέλου</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Αφαιρέθηκε ο φάκελος</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Μετονομάστηκε ο φάκελος</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Μετακινήθηκε ο φάκελος</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>αρχεία</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>φάκελοι</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>και %1 ακόμα</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Επαναφέρθηκε η βιβλιοθήκη στην κατάσταση στις</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Επαναφέρθηκε το αρχείο "%1" στην κατάσταση %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Ανακτήθηκε διεγραμένος φάκελος</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Αλλάχθηκε το όνομα της βιβλιοθήκης ή η περιγραφή</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Μόλις τώρα</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 μέρα πριν</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 μέρες πριν</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 ώρα πριν</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 ώρες πριν</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 λεπτό πριν</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 λεπτά πριν</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Δεν είναι μέρος του πιστοποιητικού></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Συγχρονισμός αυτής της βιβλιοθήκης σε:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Συγχρονισμός αυτού του φακέλου σε:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Φάκελος</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Φάκελος μόνο για ανάγνωση</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Έγγραφο</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Έγγραφο PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Αρχείο εικόνας</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Έγγραφο κειμένου</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Αρχείο ήχου</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Αρχείο βίντεο</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Έγγραφο Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Έγγραφο Powerpoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Έγγραφο Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>μεταφόρτωση λίστας αρχείου</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>Το αρχείο είναι κλειδωμένο από άλλον χρήστη</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Μη έγκυρη διαδρομή</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Σφάλμα κατά την καταλογοποίηση</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Βιβλιοθήκη "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Δεν έχει ληφθεί ακόμη αυτή η βιβλιοθήκη.</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Σφάλμα:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>RepoIcon</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>RepoName</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>TextLabel</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Κάτοχος:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Τελευταία τροποποίηση:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Μέγεθος:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Τοπική διαδρομή:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Κατάσταση:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>RepoStatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Όνομα:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Κλείσιμο</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Δεν έχει ληφθεί αυτή η βιβλιοθήκη.</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Αποτυχία ανοίγματος αρχείου "%1" από την ανύπαρκτη βιβλιοθήκη "%2"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Πρόσφατα ενημερωμένο</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Οι Βιβλιοθήκες μου</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Υποβιβλιοθήκες</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Διαμοιρασμένα με εμένα</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Διαμοιρασμένα με όλους</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Διαμοιρασμένα με ομάδες</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Συγχρονισμένες βιβλιοθήκες</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>αρχικοποίηση συγχρονισμού</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Απενεργοποίηση αυτόματου συγχρονισμού</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Ενεργοποίηση αυτόματου συγχρονισμού</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Προβολή &λεπτομερειών</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Προβολή λεπτομερειών αυτής της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Συγχρονισμός αυτής της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Συγχρονισμός της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Πρόσφατες ενημερώσεις</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Συγχρονισμός &τώρα</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Άμεσος συγχρονισμός της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Ακύρωση λήψης</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Ακύρωση λήψης αυτής της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Άνοιγμα φακέλου</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>άνοιγμα τοπικού φακέλου</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Αποσυγχρονισμός</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>αποσυχρονισμός αυτής της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Προβολή στο cloud</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>προβολή αυτής της βιβλιοθήκης στο seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Διαμοιρασμός με την χρήστη</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Διαμοιρασμός με την ομάδα</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Διαμοιρασμός της βιβλιοθήκης με την ομάδα</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Άνοιγμα του εξερευνητή αρχείων cloud</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>ανοίξτε αυτή τη βιβλιοθηκη με τον ενσωματωμένο εξερευνητή αρχείων Cloud</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>%Επανασυγχρονισμός αυτής της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>αποσυγχρόνισμός και επανασυγχρονισμός αυτής της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Αποτυχία αποσυγχρονισμού βιβλιοθήκης "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Αποτυχία ακύρωσης αυτής της εργασίας:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Η λήχη έχει ακυρωθεί</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Αδυναμία αντικατάστασης αρχείου "%1" με τον εαυτό του</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Αδυναμία διαγραφής αρχείου "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Αδυναμία μεταφόρτωσης αρχείου: "%1"</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>δοκιμάστε ξανά</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Αποτυχία λήψης πληροφοριών βιβλιοθηκών <br/>Παρακαλώ %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Προσοχή:</b> Το πιστοποιητικό ssl αυτού του διακομιστή δεν είναι έμπιστο, θέλετε να συνεχίσετε;</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Αποτυχία αρχικοποιήσης αρχείου καταγραφής: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Εντάξει</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ναι</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Όχι</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Ακύρωση</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Αντιγραφή στο πρόχειρο</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ΟΚ</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Άγνωστο σφάλμα</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Απενεργοποίηση αυτόματου συγχρονισμού</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Ενεργοποίηση αυτόματου συγχρονισμού</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Αποσύνδεση</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Προβολή κεντρικού παραθύρου</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Ρυθμίσεις</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Άνοιγμα %1 &φακέλου</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>άνοιγμα %1 φακέλου</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Άνοιγμα φακέλου &Καταγραφής</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Σχετικά</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Προβολή του κουτιού Σχετικά με την εφαρμογή</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Online βοήθεια</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Αρχείο</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>ο αυτόματος συγχρονισμός είναι απενεργοποιημένος</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Μεταφόρτωση</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Λήψη</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>άνοιγμα %1 φακέλου καταγραφής</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>άνοιγμα %1 online βοήθειας</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>κάποιοι διακομιστές δεν είναι συνδεδεμένοι</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Εμφάνιση στον φάκελο</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>δοκιμάστε ξανά</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Κατάσταση σύνδεσης διακομιστών</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>συνδεδεμένο</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>αποσυνδεδεμένο</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Κλείσιμο</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Παρακαλώ εισάγετε τον κωδικό πρόσβασης της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Εισάγετε τον κωδικό πρόσβασης για την βιβλιοθήκη %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Παρακαλώ εισάγεται τον κωδικό πρόσβασης</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Λάθος κωδικός πρόσβασης</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Άγνωστο σφάλμα</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ΟΚ</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Άκυρο</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Ρυθμίσεις</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Κανένα</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP Proxy</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 Proxy</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Διαμεσολαβητής συστήματος</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Αλλάξατε την γλώσσα. Θέλετε να γίνει επανεκκίνηση για να εφαρμοστεί;</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Η θύρα του διαμεσολαβητή είναι λανθασμένη</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Απόκρυψη του κεντρικού παραθύρου κατά την εκκίνηση</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Ειδοποίηση όταν συγχρονίζεται μια βιβλιοθήκη</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Ενεργόποιηση συγχρονισμού προσωρινών αρχείων του MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Όριο ταχύτητας λήψης (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Όριο ταχύτητας μεταφόρτωσης (kb/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Βασικό</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Να μην γίνετε αυτόματος αποσυγχρονισμός βιβλιοθηκών</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Να μην γίνετε αυτόματος αποσυγχρονισμός μίας βιβλιοθήκης όταν ο τοπικός φάκελος διαγραφεί ή είναι μη διαθέσιμος για άλλους λόγους.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Να μην γίνετε αποσυγχρονισμός μίας βιβλιοθήκης όταν δεν βρεθεί στον διακομιστή</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Να μην γίνετε αυτόματος αποσυγχρονισμός μίας βιβλιοθήκης όταν δεν βρεθεί στον διακομιστή</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Ενεργοποίηση της προσθήκης FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Ενεργοποίηση προσθήκης Explorer</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Να μην γίνετε έλεγχος του πιστοποιητικού του διακομιστή κατά τον συγχρονισμό με HTTPS</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Ενεργοποίηση συγχρονισμού με υπάρχοντα φάκελο με διαφορετικό όνομα</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Προχωρημένες ρυθμίσεις</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Γλώσσα (απαιτείται επανεκκίνηση)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Γλώσσα</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Τύπος Proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Διακομιστής:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Θύρα:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Όνομα χρήστη:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Κωδικός πρόσβασης:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Ο διακομιστής proxy απαιτεί κωδικό πρόσβασης</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Δίκτυο</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ΟΚ</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Άκυρο</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Ανάγνωση Εγγραφή</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Μόνο ανάγνωση</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Αφαίρεση κοινόχρηστου</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Ανάγνωση Εγγραφή</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Μόνο ανάγνωση</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Ομάδα</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Χρήστης</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Δικαιώματα</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Κοινή χρήση συνδέσμου</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Κοινή χρήση συνδέσμου:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Άμεση Λήψη</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Αντιγραφή στο πρόχειρο</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Μη έμπιστη σύνδεση</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>Ο %1 χρησιμοποιεί ένα μή έγκυρο πιστοποιητικό ασφαλείας. Η σύνδεση μπορεί να είναι μη ασφαλής. Θέλετε να συνεχίσετε;</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Το τωρινό RSA key ίχνος είναι %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Το προηγούμενο RSA key ίχνος είναι %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Απομνημόνευση της επιλογής μου</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ναι</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Όχι</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Άνοιγμα</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Άνοιγμα αυτού του αρχείου</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>προβολή στο &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>προβολή αυτού του αρχείου στην ιστοσελίδα</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>δοκιμάστε ξανά</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Αποτύχια λήψης πληροφορίων αρχείων με αστεράκι <br/> Παρακαλώ %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Δεν έχετε αρχεία σημειωμένα με αστεράκι ακόμη.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Σφάλματα συγχρονισμού αρχείου</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Κανένα σφάλμα συγχρονισμού.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Κάντε διπλό κλικ για άνοιγμα της βιβλιοθήκης</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Βιβλιοθήκη</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Διαδρομή</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Σφάλμα</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Ώρα</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Απεγκατάσταση %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Δεν μπορείτε να αφαιρέσετε τις πληροφορίες λογαριασμού %1;</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Απομάκρυνση των πληροφοριών του λογαριασμού</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Παράθυρο</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>κείμενο</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ναι</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Όχι</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="en_US">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>delete</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="es" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Acerca de %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Cliente %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Acerca de</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Verificar si hay actualizaciones</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>fallo al abrir la base de datos de las cuentas</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>La autorización expiró, por favor ingrese nuevamente</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Fallo al eliminar identificador de sincronización de repositorio local: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Fallo al obtener información de sincronización de repositorio del servidor: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Configuración de la Cuenta</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Dirección del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no es una dirección válida</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Fallo al guardar información de la cuenta</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Fallo al guardar los cambios: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Información de la cuenta actualizada con éxito</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Dirección del Servidor</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>¿Está seguro que desea eliminar la cuenta %1?<br><br>La cuenta será eliminada localmente. Toda información de sincronización también será eliminada. La cuenta en el servidor no se verá afectada. </translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Fallo al desincronizar bibliotecas de esta cuenta: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>click para abrir el sitio web</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>versión pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Sin cuenta</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Elegir</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Configuración de la cuenta</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Desconectarse</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>no está conectado</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Cuenta</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>servidor</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Actividad de Archivos solamente en %1 Server Professional Edition.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Fallo al obtener información de actividades. Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Éxito al subir</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Archivo "%1"
+subido con éxito.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Archivo "%1"
+falló al subir.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de Permiso!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>La autorización expiró</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>El archivo está bloqueado por %1, por favor intente más tarde</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Fallo al subir: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Fallo al crear carpeta de avatares</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Comprobando Permiso</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Tareas de Descarga</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>eliminar tareas completas</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>No hay descargas ahora.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Limpiar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Cancelar esta tarea</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>cancelar esta tarea</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Remover esta tarea</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fallo al cancelar la tarea:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Fallo al eliminar esta tarea:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimizar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favoritos</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Actividades</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Buscar</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>tasa actual de descarga</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>tasa actual de subida</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Elija una carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>sin servidor conectado</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>todos los servidores conectados</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>algunos servidores no conectados</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>De:</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimizar</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>cerrar</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Seleccione</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>o arrastre la carpeta a sincronizar</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>tasa de descarga</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>bajar</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>tasa de subida</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>subir</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Error al crear la configuración ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>No se puede crear el directorio de preconfiguración "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>falla al leer %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Crear una biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Elija una carpeta</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Creando...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Fallo al generar la clave de encriptación para esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Elija la carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La carpeta %1 no existe</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Ingrese un nombre</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Defina una contraseña</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Las contraseñas no coinciden</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Fallo al agregar descarga:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Fallo al crear biblioteca en el servidor:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Ruta:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Elija</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nombre:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>encriptada</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Repetir Contraseña:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>estado actual</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>El cliente %1 no pudo inicializarse </translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 terminó de forma inesperada</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Sincronizar carpeta "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Sincronizar con carpeta:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>sincronizar con una carpeta existente</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>crear una nueva carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Sincronizar con esta carpeta existente:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Por favor escoja una carpeta</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>La carpeta no existe</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Por favor escoja la carpeta a sincronizar.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Su organización no permite poner una biblioteca fuera de la carpeta %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Conflicto con el archivo existente "%1", por favor escoja otra carpeta.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Conflicto con la biblioteca existente "%1", por favor escoja otra carpeta.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>La carpeta "%1" ya existe. ¿Está seguro de sincronizar con esa carpeta? (los contenidos serán fusionados)</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Haga click en No para en lugar de eso sincronizar con una carpeta nueva</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>No se pudo encontrar un nombre de carpeta alternativo</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Fallo al agregar tarea de descarga:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Fallo al obtener información de descarga del repositorio:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Descargar Biblioteca</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>elija...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Contraseña para esta biblioteca:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Detalle de Modificaciones</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Archivos agregados</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Archivos eliminados</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Archivos modificados</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Carpetas agregadas</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Carpetas eliminadas</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Abrir carpeta s&uperior</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Navegador de Archivos</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Atrás</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Adelante</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Inicio</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Subir archivos</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Subir una carpeta</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>No tiene permiso para subir archivos a esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Crear una carpeta</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Refrescar</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 items</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Nombre de carpeta</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>¡Nombre de carpeta inválido!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>El nombre "%1" ya está en uso.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Fallo al obtener información de archivos<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>La carpeta está vacía</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Ingrese el nombre del archivo a guardar...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>No se puede eliminar el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Ingrese la ruta de la carpeta donde desea guardar...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>¿Desea sobreescribir el archivo "%1" existente?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>El archivo "%1" no ha sido sincronizado</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>El archivo %1 ya existe.<br/>¿Desea reemplazarlo?<br/><small>(Elija No para subirlo con un nombre alternativo).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Fallo al descargar el archivo: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Seleccione un archivo para subir</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Seleccione una carpeta a subir</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Renombrar</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>¿Realmente desea eliminar estos ítems?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Crear carpeta falló</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Bloquear archivo falló</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Seleccione un archivo para actualizar %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Renombrar falló</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Eliminar falló</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Compartir falló</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>No es posible pegar archivos en la misma carpeta</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>No es posible pegar la carpeta en una subcarpeta</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Copiar falló</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Mover falló</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Crear biblioteca falló!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>La autorización expiró</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de Permiso!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Biblioteca/Carpeta no encontrada.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Fallo al subir el archivo %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>No se puede crear carpeta de caché</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>No se puede abrir carpeta de caché</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Buscar archivos</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fallo al obtener enlace</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>Fallo al obtener información del enlace de subida para el archivo "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>Pendiente</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Subir</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Subiendo %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Descargar</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Descargando %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 de %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Fallo al subir el archivo "%1", ¿desea reintentar?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Reintentar</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Saltear</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Abortar</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Guardando</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Guardar archivo falló</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>Index progress request error %1</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Última modifiación</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Mostrar en carpeta</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostrar en carpeta</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operación cancelada</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>pendiente</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>tarea cancelada</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Error Interno del Servidor</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>bloqueado por %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Modificado</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>Modificador</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Guardar como...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Bloquear</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Renombrar</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Eliminar</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Compartir con un Grupo</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>Act&ualizar</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Copiar</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Cor&tar</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Pegar</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Ca&ncelar Descarga</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Sincronizar esta carpeta</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Esta función sólo está disponible en la versión pro
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Generar Enlace %1 para Descarga</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Compartir con un Usuario</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>G&enerar Enlace Interno %1 </translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Guardar Como En...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Des&bloquear</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>No se pueden eliminar archivos de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>No se pueden cortar archivos de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Reintentar Subir</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Eliminar versión local</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Guardar versión local como...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Abrir carpeta de caché local</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation>&Generar Enlace %1 para Subir</translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fallo al obtener enlace</translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation>El archivo "%1" está bloqueado por %2</translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation>Fallo al obtener información de bloqueo para el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation>Fallo al obtener el enlace de subida para el archivo "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Fallo al crear carpetas</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Fallo al crear archivos temporarios</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Fallo al escribir archivo en disco</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Fallo al eliminar la versión anterior del archivo descargado</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Fallo al mover archivo</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>Inicialización de %1</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Escoja carpeta %1</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Por favor elija una capeta</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inicialización incompleta. ¿Seguro que desea salir?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La carpeta %1 no existe</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Escoja una carpeta</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Por favor, escoja una carpeta. Se creará una subcarpeta %1 en ella. Esta carpeta será donde se guardarán las bibliotecas descargadas.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Elija...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Siguiente</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Verificando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Creando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Fallo al crear biblioteca predefinida
+
+La versión del servidor debe ser 2.1 o superior para esta función.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Fallo al obtener la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Fallo al crear la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Descargando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Fallo al descargar la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Se descargó la biblioteca predefinida.
+Puede hacer click en "Abrir" para verla.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Error descargando biblioteca predefinida: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Fallo al descargar biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Saltear</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Ejecutar en segundo plano</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Abrir</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Finalizar</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Descargar biblioteca predefinida</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>cargar más</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Subir archivos de registros falló</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Subir archivos de registros</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de permisos!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Biblioteca/Carpeta no encontrada.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorización expiró</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Subir arcchivos de registros falló: %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Archivos de registros subidos con éxito</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Comprimiendo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 de %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Single Sign On</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Re-conectar</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Iniciando sesión...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Error de red:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Aviso:</b> el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Dirección del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no es una dirección válida</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Ingrese el nombre de usuario</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Ingrese el nombre del equipo</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>Dirección del Servidor %1</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>La dirección del servidor no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 no es una dirección válida para el servidor. Debe comenzar con 'https://'</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Contraseña o correo incorrectos</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Demasiados intentos, por favor espere un minuto</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Error Interno del Servidor</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Fallo al iniciar sesión: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Fallo al iniciar sesión</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Servidor:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Por ejemplo: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>ó http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>estado actual</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Nombre de equipo:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Usuario:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>p.ej. laptop de Juan</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Ingreso automático</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Sesión cerrada. Por favor </translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>iniciar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Actualizar</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>"%1" está sincronizada</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Archivos subidos a "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otra aplicación. Será actualizado cuando cierre la aplicación.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>Fallo al sincronizar la carpeta %1
+Algún archivo en esta carpeta está bloqueado por otra aplicación. Será actualizada cuando cierre la aplicación.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otro usuario. Actualizaciones a este archivo no son subidas.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>Failo al indexar el archivo %1
+Por favor verifique los permisos del archivo y el espacio en disco.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>Fallo al sincronizar %1
+La ruta al archivo termina con un espacio o un punto y no puede ser creada en Windows.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>Failo al sincronizar %1
+La ruta al archivo contiene caracteres invalidos. No se sincroniza a esta computadora.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>Actualizaciones al archivo %1 son denegadas debido a los permisos de la carpeta.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>No tiene permiso para sincronizar la carpeta %1.</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation>Las actualizaciones en la biblioteca de sólo lectura %1 no serán subidas.</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation>Actualizaciones concurrentes al archivo. El archivo %1 es salvado como archivo de conflicto</translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation>La carpeta %1 es movida a la carpeta seafile-recycle-bin ya que contiene archivos que todavía no han sido subidos.</translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation>La carpeta para la biblioteca %1 fue movida o eliminada. La biblioteca está dessincronizada.</translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Compartir %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Ingrese el nombre del grupo</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Ingrese el nombre de usuario o la dirección de correo electrónico</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Actualizado con éxito</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>La operación de comapartir falló: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Eliminado con éxito</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Fallo al obtener información de compartir de la carpeta</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Fallo al obtener la información de tus grupos y contactos</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Ingrese el nombre de usuario</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Ingrese el nombre del grupo</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>No existe el grupo "%1"</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Ya has compartido con el grupo %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Ya has compartido con el usuario %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>La operación anterior todavía está en curso</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Compartir con:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Comaprtir</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Permiso:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lectura-Escritura</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>sincronizada</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexando archivos</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>iniciando sincronización</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>descargando</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>subiendo</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>sincronizando y fusionando</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>esperando sincronización</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>servidor no conectado</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>autenticando en servidor</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>sincronización automática desactivada</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconocido</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Error de red</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>No se puede resolver la dirección del proxy</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>No se puede resolver la dirección del servidor</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>No se puede conectar al servidor</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Fallo al intentar establecer una conexión segura. Por favor verifique el certificado SSL del servidor</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>La transferencia de datos fue interrumpida. Por favor verifique la red o el firewall</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Se acabó el tiempo de espera para la transferencia de datos. Por favor verifique la red o el firewall</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Redireccionamiento http inesperado del servidor. Por favor verifique la configuración del servidor</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Error del servidor</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>No hay suficiente memoria</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>Fallo al escribir los datos en el cliente. Por favor verifique el espacio en disco y los permisos de las carpetas</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Espacio de almacenamiento completo</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Biblioteca eliminada en el servidor</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Biblioteca dañada en el servidor</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicializando...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>conectando al servidor...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexando archivos...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Descargando lista de archivos...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Descargando archivos...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Creando carpeta...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Agregando cambios en el archivo...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Listo</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>verificando informacion del servidor...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Cancelando</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Cancelado</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Error SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Error de red: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Error de servidor</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>fallo al abrir la base de datos de certificados</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>El archivo "%1" no existe en "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 no encontró una aplicación para abrir %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Biblioteca "%1" creada</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Biblioteca "%1" eliminada</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Renombrar %1 a</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>No es posible descargar el ítem "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>copiar falló</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Agregado</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Borrado</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Removido</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Modificado</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Renombrado</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Agregados o modificados</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Movido</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Carpeta agregada</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Carpeta removida</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Carpeta renombrada</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Carpeta movida</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>archivos</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>carpetas</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>y otros %1</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Biblioteca revertida al estado en</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Archivo "%1" revertido al estado en %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Carpeta borrada recuperada</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Nombre de biblioteca o descripción cambiados</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Auto fusionado por el sistema %1</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Ahora</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>hace 1 día</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>hace %1 días</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>hace 1 hora</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>hace %1 horas</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>hace 1 minuto</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>hace %1 minutos</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><No es Parte del Certificado></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Sincronizar esta biblioteca con:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Sincronizar esta carpeta con:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Carpeta</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Carpeta de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Documento</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Documento PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Archivo de Imagen</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Documento de Texto</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Archivo de Audio</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Archivo de Video</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Documento de Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Documento de PowerPoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Documento de Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>La ruta "%1" está en conflicto con una ruta del sistema</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>La ruta "%1" está en conflicto con una biblioteca existente</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>subiendo lista de archivos</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>El archivo está bloqueado por otra aplicación</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>La carpeta está bloqueada por otra aplicación</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>El archivo está bloqueado por otro usuario</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>La ruta es inválida</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Error al indexar</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>La ruta finaliza con un punto o con un espacio</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>La ruta contiene caracteres inválidos como '|' or ':'</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>fallo al abrir el caché de la base de datos de archivos</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>El nombre de la biblioteca contiene caracteres inválidos, como ':', '*', '|', '?'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>Actialización de archivo denegada debido a configuración de permisos de la carpeta</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>El cliente %1 ya se está ejecutando</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>Datos internos corruptos en el cliente. Por favor intente resincronizar la biblioteca</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>No tiene permiso de escritura en la biblioteca</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>No tiene permiso para sincronizar esta carpeta</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>Todos los items eliminados de la papelera </translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>Todos los items con mas de %1 días eliminados de la papelera</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>Borrador publicado</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>Borrador creado</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>Archivo creado</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>Archivo renombrado</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>Borrador eliminado</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>Archivo eliminado</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>Archivo recuperado</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>Archivo movido</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>Archivo actualizado</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>Carpeta creada</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>Carpeta renombrada</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>Carpeta eliminada</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>Carpeta recuperada</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>Carpeta movida</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>Biblioteca creada</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>Biblioteca renombrada</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>Biblioteca eliminada</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>Biblioteca recuperada</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>Creado o actualizado un archivo en una biblioteca o carpeta sin permiso de escritura</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>Permiso denegado en el servidor</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>Actualizaciones concurrentes al archivo. El archivo es salvado como archivo de conflicto</translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>Una carpeta que podría contener archivos todavía no subidos es movida a la carpeta seafile-recycle-bin</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation>fallo al abrir la base de datos de id de errores de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Esta biblioteca aún no ha sido descargada</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Error:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>cada %1 segundos</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Icono del repositorio</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>NombreRepositorio</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Propietario:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Última modifiación:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Tamaño:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Ruta Local:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Estado:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Estado del Repositorio</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nombre:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Intervalo de Sincronización:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Esta biblioteca no ha sido descargada</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>No es posible abrir el archivo "%1" desde la biblioteca "%2", que no existe</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Actualizado Recientemente</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Mis bibliotecas</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sub Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Compartido conmigo</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Compartido con todos</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Compartido con grupos</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Bibliotecas Sincronizadas</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicializando sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactivar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Mostrar d&etalles</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Mostrar detalles de esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Sincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Sincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Actualizado Recientemente</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Sincronizar a&hora</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Sincronizar biblioteca inmediatamente</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancelar descarga</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Cancelar descarga de la biblioteca</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Abrir carpeta</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>abrir carpeta local</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>Abrir carpeta &local</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Desincronizar</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>desincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Ver en la nube</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>ver esta biblioteca en la web</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Compartir con un usuario</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Compartir esta biblioteca con un usuario</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Compartir con un grupo</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Compartir esta biblioteca con un grupo</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Abrir navegador de archivos</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>abrir esta biblioteca en el navegador de archivos incorporado</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>A&bandonar compartido</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>abandonar compartido</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Resincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>desincronizar y resincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Establecer &Intervalo de sincronización</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>establecer intervalo de sincronización para esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>¿Seguro que desea desincronizar la biblioteca "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>¿Seguro que desea resincronizar la biblioteca "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>¿Está seguro de sobreescribir el archivo "%1"?</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Fallo al desincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>¿Seguro que desea abandonar el compartido "%1"?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Abandonar compartido falló</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fallo al cancelar la tarea:
+
+.%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>La descarga fue cancelada</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>No es posible sobreescribir el archivo "%1" con él mismo</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>No se puede eliminar el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Fallo al subir el archivo: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Intervalo de Sincronización (en segundos):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Establecer Intervalo de Sincronización para la Biblioteca "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Buscar bibliotecas</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Fallo al obtener información de las bibliotecas<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation>Aviso: el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Fallo al crear registro: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>fallo al guardar el id del cliente</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>fallo al acceder a %1</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>Id del cliente incorrecto</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>fallo al leer %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>Enlace Interno %1</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar al portapapeles</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>Enlace interno %1:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>%1 Desktop Access Link:</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>error interno: fallo al conectar con el servicio</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactivar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activar auto sincronización</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Cerrar</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Ventana principal</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Configuración</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Abrir &carpeta %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>abrir carpeta %1</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Abrir &registros</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Mostrar errores al sincronizar archivos</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>Acerca &de</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Muestra la información de la aplicación</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Ayuda en línea</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Archivo</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>auto sincronización desactivada</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Subiendo</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Descargando</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>abrir registros %1</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>abrir ayuda en línea %1</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>algunos servidores no contectados</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Subir archivos de registros</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>subir %1 archivos de registros</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Por favor, primero ingrese</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>Reparar extensión explorer</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>Iconos de estado de sincronización para Explorer reparados con éxito</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>Fallo al reparar iconos de estado de sincronización para Explorer</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>tiene algún error de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Mostrar en carpeta</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostrar en carpeta</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Buscar archivos</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Fallo al buscar<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Estado de conexión de servidores</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>conectado</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>desconectado</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Por favor suministre la contraseña para la biblioteca</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Suministre la contraseña para la biblioteca %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Contraseña incorrecta</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Configuración</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Iniciar automáticamente %1 después del inicio de sesión</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Ocultar el icono de %1 de la barra</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Ninguno</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>Proxy HTTP</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Proxy Socks5</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Proxy del Sistema</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Ha cambiado el idioma. ¿Desea reiniciar para aplicar el cambio?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>La dirección del proxy no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>El puerto del proxy es incorrecto</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>El nombre de usuario del proxy no puede estar vacío</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>La contraseña del proxy no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Ocultar ventana principal al iniciar</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Notificar al sincronizar bibliotecas</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Habilitar la sincronización de archivos temporarios de MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Límite de velocidad de descarga (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Límite de velocidad de subida (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Básico</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>No desincronizar automáticamente una biblioteca</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>No desincronizar automáticamente una biblioteca cuando la carpeta local haya sido removida o no esté accesible por otros motivos.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>No desincronizar una biblioteca cuando no se encuentre en el servidor</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>No desincronizar automáticamente una biblioteca cuando no se encuentre en el servidor</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Habilitar extensión FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Habilitar extensión Explorer</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Verificar si hay actualizaciones automáticamente</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>No verificar el certificado del servidor en sincronización HTTPS</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Habilitar sincronización con una carpeta existente con distinto nombre</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Avanzado</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Idioma (requiere reinicio)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Idioma</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Tipo de Proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Dirección:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Puerto:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Usuario:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>El servidor proxy requiere una contraseña</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Red</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lectura Escritura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Eliminar Compartido</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Click para editar</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Creado por %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lectura Escritura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Grupo</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Usuario</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Permiso</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>La operación anterior todavía está en curso</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Enlace para Compartir</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Enlace para compartir:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Descarga Directa</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar al portapapeles</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation>Enlace de Subida</translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation>Enlace de subida:</translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Conexión no confiable</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 utiliza un certificado de seguridad inválido. La conexión podría no ser segura. Desea continuar?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>La huella digital de la clave RSA actual es %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>La huella digital de la clave RSA anterior es %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Recordar mi elección</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Abrir este archivo</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>ver en la &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>ver este archivo en el sitio web</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Fallo al obtener información de archivos favoritos<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Aún no tiene archivos favoritos.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Errores al Sincronizar Archivos</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>No hay errores de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Doble click para abrir la biblioteca</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Hora</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Ingrese el identificador de autenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Auenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Por favor ingrese el identificador de autenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Recordar este dispositivo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Desinstalar %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>¿Seguro que desea eliminar la información de la cuenta %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Eliminando información de la cuenta...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>texto</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_AR" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Acerca de %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Cliente %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Acerca de</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Verificar si hay actualizaciones</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>fallo al abrir la base de datos de las cuentas</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>La autorización expiró, por favor ingrese nuevamente</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Fallo al eliminar identificador de sincronización de repositorio local: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Fallo al obtener información de sincronización de repositorio del servidor: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Configuración de la Cuenta</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Dirección del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no es una dirección válida</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Fallo al guardar información de la cuenta</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Fallo al guardar los cambios: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Información de la cuenta actualizada con éxito</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Dirección del Servidor</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>¿Está seguro que desea eliminar la cuenta %1?<br><br>La cuenta será eliminada localmente. Toda información de sincronización también será eliminada. La cuenta en el servidor no se verá afectada. </translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Fallo al desincronizar bibliotecas de esta cuenta: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>click para abrir el sitio web</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>versión pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Sin cuenta</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Elegir</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Configuración de la cuenta</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Desconectarse</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>no está conectado</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Cuenta</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>servidor</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Actividad de Archivos solamente en %1 Server Professional Edition.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Fallo al obtener información de actividades. Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Éxito al subir</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Archivo "%1"
+subido con éxito.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Archivo "%1"
+falló al subir.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de Permiso!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>La autorización expiró</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>El archivo está bloqueado por %1, por favor intente más tarde</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Fallo al subir: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Fallo al crear carpeta de avatares</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Comprobando Permiso</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Tareas de Descarga</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>eliminar tareas completas</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>No hay descargas ahora.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Limpiar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Cancelar esta tarea</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>cancelar esta tarea</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Remover esta tarea</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fallo al cancelar la tarea:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Fallo al eliminar esta tarea:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimizar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favoritos</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Actividades</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Buscar</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>tasa actual de descarga</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>tasa actual de subida</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Elija una carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>sin servidor conectado</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>todos los servidores conectados</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>algunos servidores no conectados</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>De:</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimizar</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>cerrar</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Seleccione</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>o arrastre la carpeta a sincronizar</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>tasa de descarga</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>bajar</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>tasa de subida</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>subir</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Error al crear la configuración ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>No se puede crear el directorio de preconfiguración "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>falla al leer %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Crear una biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Elija una carpeta</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Creando...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Fallo al generar la clave de encriptación para esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Elija la carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La carpeta %1 no existe</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Ingrese un nombre</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Defina una contraseña</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Las contraseñas no coinciden</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Fallo al agregar descarga:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Fallo al crear biblioteca en el servidor:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Ruta:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Elija</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nombre:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>encriptada</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Repetir Contraseña:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>estado actual</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>El cliente %1 no pudo inicializarse </translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 terminó de forma inesperada</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Sincronizar carpeta "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Sincronizar con carpeta:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>sincronizar con una carpeta existente</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>crear una nueva carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Sincronizar con esta carpeta existente:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Por favor escoja una carpeta</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>La carpeta no existe</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Por favor escoja la carpeta a sincronizar.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Su organización no permite poner una biblioteca fuera de la carpeta %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Conflicto con el archivo existente "%1", por favor escoja otra carpeta.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Conflicto con la biblioteca existente "%1", por favor escoja otra carpeta.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>La carpeta "%1" ya existe. ¿Está seguro de sincronizar con esa carpeta? (los contenidos serán fusionados)</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Haga click en No para en lugar de eso sincronizar con una carpeta nueva</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>No se pudo encontrar un nombre de carpeta alternativo</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Fallo al agregar tarea de descarga:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Fallo al obtener información de descarga del repositorio:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Descargar Biblioteca</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>elija...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Contraseña para esta biblioteca:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Detalle de Modificaciones</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Archivos agregados</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Archivos eliminados</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Archivos modificados</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Carpetas agregadas</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Carpetas eliminadas</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Abrir carpeta s&uperior</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Navegador de Archivos</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Atrás</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Adelante</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Inicio</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Subir archivos</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Subir una carpeta</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>No tiene permiso para subir archivos a esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Crear una carpeta</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Refrescar</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 items</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Nombre de carpeta</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>¡Nombre de carpeta inválido!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>El nombre "%1" ya está en uso.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Fallo al obtener información de archivos<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>La carpeta está vacía</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Ingrese el nombre del archivo a guardar...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>No se puede eliminar el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Ingrese la ruta de la carpeta donde desea guardar...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>¿Desea sobreescribir el archivo "%1" existente?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>El archivo "%1" no ha sido sincronizado</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>El archivo %1 ya existe.<br/>¿Desea reemplazarlo?<br/><small>(Elija No para subirlo con un nombre alternativo).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Fallo al descargar el archivo: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Seleccione un archivo para subir</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Seleccione una carpeta a subir</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Renombrar</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>¿Realmente desea eliminar estos ítems?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Crear carpeta falló</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Bloquear archivo falló</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Seleccione un archivo para actualizar %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Renombrar falló</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Eliminar falló</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Compartir falló</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>No es posible pegar archivos en la misma carpeta</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>No es posible pegar la carpeta en una subcarpeta</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Copiar falló</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Mover falló</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Crear biblioteca falló!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>La autorización expiró</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de Permiso!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Biblioteca/Carpeta no encontrada.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Fallo al subir el archivo %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>No se puede crear carpeta de caché</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>No se puede abrir carpeta de caché</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Buscar archivos</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fallo al obtener enlace</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>Fallo al obtener información del enlace de subida para el archivo "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>Pendiente</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Subir</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Subiendo %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Descargar</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Descargando %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 de %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Fallo al subir el archivo "%1", ¿desea reintentar?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Reintentar</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Saltear</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Abortar</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Guardando</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Guardar archivo falló</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>Index progress request error %1</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Última modifiación</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Mostrar en carpeta</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostrar en carpeta</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operación cancelada</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>pendiente</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>tarea cancelada</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Error Interno del Servidor</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>bloqueado por %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Modificado</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>Modificador</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Guardar como...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Bloquear</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Renombrar</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Eliminar</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Compartir con un Grupo</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>Act&ualizar</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Copiar</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Cor&tar</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Pegar</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Ca&ncelar Descarga</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Sincronizar esta carpeta</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Esta función sólo está disponible en la versión pro
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Generar Enlace %1 para Descarga</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Compartir con un Usuario</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>G&enerar Enlace Interno %1 </translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Guardar Como En...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Des&bloquear</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>No se pueden eliminar archivos de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>No se pueden cortar archivos de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Reintentar Subir</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Eliminar versión local</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Guardar versión local como...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Abrir carpeta de caché local</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation>&Generar Enlace %1 para Subir</translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fallo al obtener enlace</translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation>El archivo "%1" está bloqueado por %2</translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation>Fallo al obtener información de bloqueo para el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation>Fallo al obtener el enlace de subida para el archivo "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Fallo al crear carpetas</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Fallo al crear archivos temporarios</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Fallo al escribir archivo en disco</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Fallo al eliminar la versión anterior del archivo descargado</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Fallo al mover archivo</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>Inicialización de %1</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Escoja carpeta %1</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Por favor elija una capeta</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inicialización incompleta. ¿Seguro que desea salir?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La carpeta %1 no existe</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Escoja una carpeta</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Por favor, escoja una carpeta. Se creará una subcarpeta %1 en ella. Esta carpeta será donde se guardarán las bibliotecas descargadas.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Elija...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Siguiente</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Verificando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Creando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Fallo al crear biblioteca predefinida
+
+La versión del servidor debe ser 2.1 o superior para esta función.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Fallo al obtener la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Fallo al crear la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Descargando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Fallo al descargar la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Se descargó la biblioteca predefinida.
+Puede hacer click en "Abrir" para verla.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Error descargando biblioteca predefinida: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Fallo al descargar biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Saltear</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Ejecutar en segundo plano</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Abrir</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Finalizar</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Descargar biblioteca predefinida</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>cargar más</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Subir archivos de registros falló</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Subir archivos de registros</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de permisos!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Biblioteca/Carpeta no encontrada.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorización expiró</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Subir arcchivos de registros falló: %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Archivos de registros subidos con éxito</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Comprimiendo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 de %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Single Sign On</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Re-conectar</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Iniciando sesión...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Error de red:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Aviso:</b> el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Dirección del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no es una dirección válida</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Ingrese el nombre de usuario</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Ingrese el nombre del equipo</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>Dirección del Servidor %1</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>La dirección del servidor no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 no es una dirección válida para el servidor. Debe comenzar con 'https://'</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Contraseña o correo incorrectos</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Demasiados intentos, por favor espere un minuto</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Error Interno del Servidor</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Fallo al iniciar sesión: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Fallo al iniciar sesión</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Servidor:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Por ejemplo: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>ó http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>estado actual</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Nombre de equipo:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Usuario:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>p.ej. laptop de Juan</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Ingreso automático</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Sesión cerrada. Por favor </translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>iniciar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Actualizar</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>"%1" está sincronizada</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Archivos subidos a "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otra aplicación. Será actualizado cuando cierre la aplicación.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>Fallo al sincronizar la carpeta %1
+Algún archivo en esta carpeta está bloqueado por otra aplicación. Será actualizada cuando cierre la aplicación.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otro usuario. Actualizaciones a este archivo no son subidas.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>Failo al indexar el archivo %1
+Por favor verifique los permisos del archivo y el espacio en disco.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>Fallo al sincronizar %1
+La ruta al archivo termina con un espacio o un punto y no puede ser creada en Windows.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>Failo al sincronizar %1
+La ruta al archivo contiene caracteres invalidos. No se sincroniza a esta computadora.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>Actualizaciones al archivo %1 son denegadas debido a los permisos de la carpeta.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>No tiene permiso para sincronizar la carpeta %1.</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation>Las actualizaciones en la biblioteca de sólo lectura %1 no serán subidas.</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation>Actualizaciones concurrentes al archivo. El archivo %1 es salvado como archivo de conflicto</translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation>La carpeta %1 es movida a la carpeta seafile-recycle-bin ya que contiene archivos que todavía no han sido subidos.</translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation>La carpeta para la biblioteca %1 fue movida o eliminada. La biblioteca está dessincronizada.</translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Compartir %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Ingrese el nombre del grupo</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Ingrese el nombre de usuario o la dirección de correo electrónico</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Actualizado con éxito</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>La operación de comapartir falló: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Eliminado con éxito</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Fallo al obtener información de compartir de la carpeta</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Fallo al obtener la información de tus grupos y contactos</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Ingrese el nombre de usuario</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Ingrese el nombre del grupo</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>No existe el grupo "%1"</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Ya has compartido con el grupo %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Ya has compartido con el usuario %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>La operación anterior todavía está en curso</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Compartir con:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Comaprtir</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Permiso:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lectura-Escritura</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>sincronizada</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexando archivos</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>iniciando sincronización</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>descargando</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>subiendo</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>sincronizando y fusionando</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>esperando sincronización</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>servidor no conectado</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>autenticando en servidor</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>sincronización automática desactivada</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconocido</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Error de red</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>No se puede resolver la dirección del proxy</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>No se puede resolver la dirección del servidor</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>No se puede conectar al servidor</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Fallo al intentar establecer una conexión segura. Por favor verifique el certificado SSL del servidor</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>La transferencia de datos fue interrumpida. Por favor verifique la red o el firewall</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Se acabó el tiempo de espera para la transferencia de datos. Por favor verifique la red o el firewall</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Redireccionamiento http inesperado del servidor. Por favor verifique la configuración del servidor</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Error del servidor</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>No hay suficiente memoria</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>Fallo al escribir los datos en el cliente. Por favor verifique el espacio en disco y los permisos de las carpetas</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Espacio de almacenamiento completo</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Biblioteca eliminada en el servidor</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Biblioteca dañada en el servidor</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicializando...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>conectando al servidor...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexando archivos...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Descargando lista de archivos...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Descargando archivos...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Creando carpeta...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Agregando cambios en el archivo...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Listo</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>verificando informacion del servidor...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Cancelando</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Cancelado</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Error SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Error de red: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Error de servidor</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>fallo al abrir la base de datos de certificados</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>El archivo "%1" no existe en "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 no encontró una aplicación para abrir %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Biblioteca "%1" creada</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Biblioteca "%1" eliminada</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Renombrar %1 a</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>No es posible descargar el ítem "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>copiar falló</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Agregado</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Borrado</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Removido</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Modificado</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Renombrado</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Agregados o modificados</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Movido</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Carpeta agregada</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Carpeta removida</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Carpeta renombrada</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Carpeta movida</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>archivos</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>carpetas</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>y otros %1</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Biblioteca revertida al estado en</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Archivo "%1" revertido al estado en %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Carpeta borrada recuperada</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Nombre de biblioteca o descripción cambiados</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Auto fusionado por el sistema %1</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Ahora</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>hace 1 día</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>hace %1 días</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>hace 1 hora</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>hace %1 horas</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>hace 1 minuto</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>hace %1 minutos</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><No es Parte del Certificado></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Sincronizar esta biblioteca con:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Sincronizar esta carpeta con:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Carpeta</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Carpeta de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Documento</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Documento PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Archivo de Imagen</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Documento de Texto</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Archivo de Audio</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Archivo de Video</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Documento de Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Documento de PowerPoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Documento de Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>La ruta "%1" está en conflicto con una ruta del sistema</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>La ruta "%1" está en conflicto con una biblioteca existente</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>subiendo lista de archivos</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>El archivo está bloqueado por otra aplicación</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>La carpeta está bloqueada por otra aplicación</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>El archivo está bloqueado por otro usuario</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>La ruta es inválida</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Error al indexar</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>La ruta finaliza con un punto o con un espacio</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>La ruta contiene caracteres inválidos como '|' or ':'</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>fallo al abrir el caché de la base de datos de archivos</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>El nombre de la biblioteca contiene caracteres inválidos, como ':', '*', '|', '?'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>Actialización de archivo denegada debido a configuración de permisos de la carpeta</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>El cliente %1 ya se está ejecutando</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>Datos internos corruptos en el cliente. Por favor intente resincronizar la biblioteca</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>No tiene permiso de escritura en la biblioteca</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>No tiene permiso para sincronizar esta carpeta</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>Todos los items eliminados de la papelera </translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>Todos los items con mas de %1 días eliminados de la papelera</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>Borrador publicado</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>Borrador creado</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>Archivo creado</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>Archivo renombrado</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>Borrador eliminado</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>Archivo eliminado</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>Archivo recuperado</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>Archivo movido</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>Archivo actualizado</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>Carpeta creada</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>Carpeta renombrada</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>Carpeta eliminada</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>Carpeta recuperada</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>Carpeta movida</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>Biblioteca creada</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>Biblioteca renombrada</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>Biblioteca eliminada</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>Biblioteca recuperada</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>Creado o actualizado un archivo en una biblioteca o carpeta sin permiso de escritura</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>Permiso denegado en el servidor</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>Actualizaciones concurrentes al archivo. El archivo es salvado como archivo de conflicto</translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>Una carpeta que podría contener archivos todavía no subidos es movida a la carpeta seafile-recycle-bin</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation>fallo al abrir la base de datos de id de errores de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Esta biblioteca aún no ha sido descargada</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Error:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>cada %1 segundos</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Icono del repositorio</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>NombreRepositorio</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Propietario:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Última modifiación:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Tamaño:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Ruta Local:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Estado:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Estado del Repositorio</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nombre:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Intervalo de Sincronización:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Esta biblioteca no ha sido descargada</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>No es posible abrir el archivo "%1" desde la biblioteca "%2", que no existe</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Actualizado Recientemente</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Mis bibliotecas</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sub Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Compartido conmigo</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Compartido con todos</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Compartido con grupos</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Bibliotecas Sincronizadas</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicializando sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactivar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Mostrar d&etalles</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Mostrar detalles de esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Sincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Sincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Actualizado Recientemente</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Sincronizar a&hora</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Sincronizar biblioteca inmediatamente</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancelar descarga</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Cancelar descarga de la biblioteca</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Abrir carpeta</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>abrir carpeta local</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>Abrir carpeta &local</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Desincronizar</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>desincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Ver en la nube</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>ver esta biblioteca en la web</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Compartir con un usuario</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Compartir esta biblioteca con un usuario</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Compartir con un grupo</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Compartir esta biblioteca con un grupo</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Abrir navegador de archivos</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>abrir esta biblioteca en el navegador de archivos incorporado</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>A&bandonar compartido</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>abandonar compartido</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Resincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>desincronizar y resincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Establecer &Intervalo de sincronización</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>establecer intervalo de sincronización para esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>¿Seguro que desea desincronizar la biblioteca "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>¿Seguro que desea resincronizar la biblioteca "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>¿Está seguro de sobreescribir el archivo "%1"?</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Fallo al desincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>¿Seguro que desea abandonar el compartido "%1"?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Abandonar compartido falló</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fallo al cancelar la tarea:
+
+.%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>La descarga fue cancelada</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>No es posible sobreescribir el archivo "%1" con él mismo</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>No se puede eliminar el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Fallo al subir el archivo: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Intervalo de Sincronización (en segundos):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Establecer Intervalo de Sincronización para la Biblioteca "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Buscar bibliotecas</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Fallo al obtener información de las bibliotecas<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation>Aviso: el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Fallo al crear registro: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>fallo al guardar el id del cliente</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>fallo al acceder a %1</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>Id del cliente incorrecto</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>fallo al leer %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>Enlace Interno %1</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar al portapapeles</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>Enlace interno %1:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>%1 Desktop Access Link:</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>error interno: fallo al conectar con el servicio</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactivar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activar auto sincronización</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Cerrar</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Ventana principal</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Configuración</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Abrir &carpeta %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>abrir carpeta %1</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Abrir &registros</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Mostrar errores al sincronizar archivos</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>Acerca &de</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Muestra la información de la aplicación</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Ayuda en línea</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Archivo</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>auto sincronización desactivada</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Subiendo</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Descargando</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>abrir registros %1</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>abrir ayuda en línea %1</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>algunos servidores no contectados</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Subir archivos de registros</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>subir %1 archivos de registros</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Por favor, primero ingrese</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>Reparar extensión explorer</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>Iconos de estado de sincronización para Explorer reparados con éxito</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>Fallo al reparar iconos de estado de sincronización para Explorer</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>tiene algún error de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Mostrar en carpeta</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostrar en carpeta</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Buscar archivos</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Fallo al buscar<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Estado de conexión de servidores</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>conectado</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>desconectado</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Por favor suministre la contraseña para la biblioteca</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Suministre la contraseña para la biblioteca %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Contraseña incorrecta</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Configuración</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Iniciar automáticamente %1 después del inicio de sesión</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Ocultar el icono de %1 de la barra</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Ninguno</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>Proxy HTTP</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Proxy Socks5</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Proxy del Sistema</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Ha cambiado el idioma. ¿Desea reiniciar para aplicar el cambio?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>La dirección del proxy no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>El puerto del proxy es incorrecto</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>El nombre de usuario del proxy no puede estar vacío</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>La contraseña del proxy no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Ocultar ventana principal al iniciar</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Notificar al sincronizar bibliotecas</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Habilitar la sincronización de archivos temporarios de MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Límite de velocidad de descarga (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Límite de velocidad de subida (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Básico</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>No desincronizar automáticamente una biblioteca</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>No desincronizar automáticamente una biblioteca cuando la carpeta local haya sido removida o no esté accesible por otros motivos.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>No desincronizar una biblioteca cuando no se encuentre en el servidor</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>No desincronizar automáticamente una biblioteca cuando no se encuentre en el servidor</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Habilitar extensión FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Habilitar extensión Explorer</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Verificar si hay actualizaciones automáticamente</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>No verificar el certificado del servidor en sincronización HTTPS</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Habilitar sincronización con una carpeta existente con distinto nombre</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Avanzado</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Idioma (requiere reinicio)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Idioma</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Tipo de Proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Dirección:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Puerto:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Usuario:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>El servidor proxy requiere una contraseña</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Red</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lectura Escritura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Eliminar Compartido</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Click para editar</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Creado por %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lectura Escritura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Grupo</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Usuario</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Permiso</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>La operación anterior todavía está en curso</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Enlace para Compartir</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Enlace para compartir:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Descarga Directa</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar al portapapeles</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation>Enlace de Subida</translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation>Enlace de subida:</translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Conexión no confiable</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 utiliza un certificado de seguridad inválido. La conexión podría no ser segura. Desea continuar?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>La huella digital de la clave RSA actual es %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>La huella digital de la clave RSA anterior es %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Recordar mi elección</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Abrir este archivo</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>ver en la &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>ver este archivo en el sitio web</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Fallo al obtener información de archivos favoritos<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Aún no tiene archivos favoritos.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Errores al Sincronizar Archivos</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>No hay errores de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Doble click para abrir la biblioteca</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Hora</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Ingrese el identificador de autenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Auenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Por favor ingrese el identificador de autenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Recordar este dispositivo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Desinstalar %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>¿Seguro que desea eliminar la información de la cuenta %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Eliminando información de la cuenta...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>texto</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="es_MX" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Acerca de %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Cliente %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Acerca de</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Verificar si hay actualizaciones</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>fallo al abrir la base de datos de las cuentas</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>La autorización expiró, por favor ingrese nuevamente</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Fallo al eliminar identificador de sincronización de repositorio local: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Fallo al obtener información de sincronización de repositorio del servidor: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Configuración de la Cuenta</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Dirección del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no es una dirección válida</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Fallo al guardar información de la cuenta</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Fallo al guardar los cambios: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Información de la cuenta actualizada con éxito</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Dirección del Servidor</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>¿Está seguro que desea eliminar la cuenta %1?<br><br>La cuenta será eliminada localmente. Toda información de sincronización también será eliminada. La cuenta en el servidor no se verá afectada. </translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Fallo al desincronizar bibliotecas de esta cuenta: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>click para abrir el sitio web</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>versión pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Sin cuenta</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Elegir</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Configuración de la cuenta</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Eliminar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Desconectarse</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>no está conectado</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Cuenta</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>servidor</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Actividad de Archivos solamente en %1 Server Professional Edition.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Fallo al obtener información de actividades. Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Éxito al subir</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Archivo "%1"
+subido con éxito.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Archivo "%1"
+falló al subir.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de Permiso!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>La autorización expiró</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>El archivo está bloqueado por %1, por favor intente más tarde</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Fallo al subir: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Fallo al crear carpeta de avatares</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Comprobando Permiso</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Tareas de Descarga</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>Eliminar tareas completas</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>No hay descargas ahora.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Limpiar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Cancelar esta tarea</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>cancela esta tarea</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Remover esta tarea</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fallo al cancelar la tarea:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Fallo al eliminar esta tarea:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimizar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favoritos</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Actividades</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Buscar</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>tasa actual de descarga</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>tasa actual de subida</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Elija una carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>sin servidor conectado</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>todos los servidores conectados</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>algunos servidores no conectados</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>De:</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimizar</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>cerrar</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Seleccione</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>o arrastre la carpeta a sincronizar</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>tasa de descarga</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>bajar</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>tasa de subida</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>subir</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Error al crear la configuración ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>No se puede crear el directorio de preconfiguración "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>falla al leer %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Crear una biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Escoja una carpeta</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Creando..</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Fallo al generar la clave de encriptación para esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Escoja directorio para sincronizar</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La carpeta %1 no existe</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Ingrese un nombre</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Defina una contraseña</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Las contraseñas no coinciden</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Fallo al agregar descarga:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Fallo al crear biblioteca en el servidor:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Ruta:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Escoja</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nombre:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>encriptado</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Repetir Contraseña:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>estado actual</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>El cliente %1 no pudo inicializarse </translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 terminó de forma inesperada</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Sincronizar carpeta "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Sincronizar con carpeta:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>o</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>sincronizar con una carpeta existente</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>crear una nueva carpeta para sincronizar</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Sincronizar con esta carpeta existente:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Por favor escoja una carpeta</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>La carpeta no existe</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Por favor escoja la carpeta a sincronizar.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Su organización no permite poner una biblioteca fuera de la carpeta %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Conflicto con el archivo existente "%1", por favor escoja otra carpeta.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Conflicto con la biblioteca existente "%1", por favor escoja otra carpeta.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>La carpeta "%1" ya existe. ¿Está seguro de sincronizar con esa carpeta? (los contenidos serán fusionados)</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Haga click en No para en lugar de eso sincronizar con una carpeta nueva</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>No se pudo encontrar un nombre de carpeta alternativo</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Fallo al agregar tarea de descarga:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Fallo al obtener información de descarga del repositorio:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Descargar Biblioteca</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>elija...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Contraseña para esta biblioteca:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Detalle de Modificaciones</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Archivos agregados</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Archivos eliminados</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Archivos modificados</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Carpetas agregadas</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Carpetas eliminadas</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Abrir carpeta s&uperior</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Navegador de Archivos</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Atrás</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Adelante</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Inicio</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Subir archivos</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Subir una carpeta</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>No tiene permiso para subir archivos a esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Crear una carpeta</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Refrescar</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 items</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Nombre de carpeta</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>¡Nombre de carpeta inválido!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>El nombre "%1" ya está en uso.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Fallo al obtener información de archivos<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>La carpeta está vacía</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Ingrese el nombre del archivo a guardar...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>No se puede eliminar el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Ingrese la ruta de la carpeta donde desea guardar...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>¿Desea sobreescribir el archivo "%1" existente?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>El archivo "%1" no ha sido sincronizado</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>El archivo %1 ya existe.<br/>¿Desea reemplazarlo?<br/><small>(Elija No para subirlo con un nombre alternativo).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Fallo al descargar el archivo: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Seleccione un archivo para subir</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Seleccione una carpeta a subir</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Renombrar</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>¿Realmente desea eliminar estos ítems?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Crear carpeta falló</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Bloquear archivo falló</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Seleccione un archivo para actualizar %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Renombrar falló</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Eliminar falló</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Compartir falló</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>No es posible pegar archivos en la misma carpeta</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>No es posible pegar la carpeta en una subcarpeta</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Copiar falló</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Mover falló</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Crear biblioteca falló!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>La autorización expiró</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de Permiso!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Biblioteca/Carpeta no encontrada.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Fallo al subir el archivo %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>No se puede crear carpeta de caché</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>No se puede abrir carpeta de caché</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Buscar archivos</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fallo al obtener enlace</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>Fallo al obtener información del enlace de subida para el archivo "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>Pendiente</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Subir</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Subiendo %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Descargar</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Descargando %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 de %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Fallo al subir el archivo "%1", ¿desea reintentar?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Reintentar</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Saltear</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Abortar</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Guardando</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Guardar archivo falló</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>Index progress request error %1</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Última modifiación</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Mostrar en carpeta</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostrar en carpeta</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operación cancelada</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>pendiente</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>tarea cancelada</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Error Interno del Servidor</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>bloqueado por %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nombre</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Tamaño</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Modificado</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>Modificador</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Guardar como...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Bloquear</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Renombrar</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Eliminar</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Compartir con un Grupo</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>Act&ualizar</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Copiar</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Cor&tar</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Pegar</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Ca&ncelar Descarga</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Sincronizar esta carpeta</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Esta función sólo está disponible en la versión pro
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Generar Enlace %1 para Descarga</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Compartir con un Usuario</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>G&enerar Enlace Interno %1 </translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Guardar Como En...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Des&bloquear</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>No se pueden eliminar archivos de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>No se pueden cortar archivos de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Reintentar Subir</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Eliminar versión local</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Guardar versión local como...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Abrir carpeta de caché local</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation>&Generar Enlace %1 para Subir</translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Fallo al obtener enlace</translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation>El archivo "%1" está bloqueado por %2</translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation>Fallo al obtener información de bloqueo para el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation>Fallo al obtener el enlace de subida para el archivo "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Fallo al crear carpetas</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Fallo al crear archivos temporarios</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Fallo al escribir archivo en disco</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Fallo al eliminar la versión anterior del archivo descargado</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Fallo al mover archivo</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>Inicialización de %1</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Escoja carpeta %1</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Por favor elija una capeta</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inicialización incompleta. ¿Seguro que desea salir?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La carpeta %1 no existe</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Escoja una carpeta</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Por favor, escoja una carpeta. Se creará una subcarpeta %1 en ella. Esta carpeta será donde se guardarán las bibliotecas descargadas.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Elija...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Siguiente</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Verificando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Creando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Fallo al crear biblioteca predefinida
+
+La versión del servidor debe ser 2.1 o superior para esta función.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Fallo al obtener la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Fallo al crear la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Descargando biblioteca predefinida...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Fallo al descargar la biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Se descargó la biblioteca predefinida.
+Puede hacer click en "Abrir" para verla.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Error descargando biblioteca predefinida: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Fallo al descargar biblioteca predefinida:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organiza los archivos en bibliotecas
+¿Desea descargar la biblioteca predefinida?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Saltear</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Ejecutar en segundo plano</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Abrir</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Finalizar</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Descargar biblioteca predefinida</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>cargar más</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Subir archivos de registros falló</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Subir archivos de registros</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Error de permisos!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Biblioteca/Carpeta no encontrada.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorización expiró</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Subir arcchivos de registros falló: %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Archivos de registros subidos con éxito</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Comprimiendo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 de %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Single Sign On</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Re-conectar</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Iniciando sesión...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Error de red:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Aviso:</b> el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Dirección del servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 no es una dirección válida</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Ingrese el nombre de usuario</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Ingrese el nombre del equipo</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>Dirección del Servidor %1</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>La dirección del servidor no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 no es una dirección válida para el servidor. Debe comenzar con 'https://'</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Contraseña o correo incorrectos</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Demasiados intentos, por favor espere un minuto</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Error Interno del Servidor</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Fallo al iniciar sesión: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Fallo al iniciar sesión</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Servidor:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Por ejemplo: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>ó http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>estado actual</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Nombre de equipo:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Usuario:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>p.ej. laptop de Juan</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Ingreso automático</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Sesión cerrada. Por favor </translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>iniciar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Agregar una cuenta</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Actualizar</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>"%1" está sincronizada</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Archivos subidos a "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otra aplicación. Será actualizado cuando cierre la aplicación.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>Fallo al sincronizar la carpeta %1
+Algún archivo en esta carpeta está bloqueado por otra aplicación. Será actualizada cuando cierre la aplicación.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>Fallo al sincronizar el archivo %1
+El archivo está bloqueado por otro usuario. Actualizaciones a este archivo no son subidas.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>Failo al indexar el archivo %1
+Por favor verifique los permisos del archivo y el espacio en disco.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>Fallo al sincronizar %1
+La ruta al archivo termina con un espacio o un punto y no puede ser creada en Windows.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>Failo al sincronizar %1
+La ruta al archivo contiene caracteres invalidos. No se sincroniza a esta computadora.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>Actualizaciones al archivo %1 son denegadas debido a los permisos de la carpeta.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>No tiene permiso para sincronizar la carpeta %1.</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation>Las actualizaciones en la biblioteca de sólo lectura %1 no serán subidas.</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation>Actualizaciones concurrentes al archivo. El archivo %1 es salvado como archivo de conflicto</translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation>La carpeta %1 es movida a la carpeta seafile-recycle-bin ya que contiene archivos que todavía no han sido subidos.</translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation>La carpeta para la biblioteca %1 fue movida o eliminada. La biblioteca está dessincronizada.</translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Compartir %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Ingrese el nombre del grupo</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Ingrese el nombre de usuario o la dirección de correo electrónico</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Actualizado con éxito</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>La operación de comapartir falló: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Eliminado con éxito</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Fallo al obtener información de compartir de la carpeta</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Fallo al obtener la información de tus grupos y contactos</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Ingrese el nombre de usuario</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Ingrese el nombre del grupo</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>No existe el grupo "%1"</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Ya has compartido con el grupo %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Ya has compartido con el usuario %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>La operación anterior todavía está en curso</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Compartir con:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Comaprtir</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Permiso:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lectura-Escritura</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>sincronizada</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexando archivos</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>iniciando sincronización</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>descargando</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>subiendo</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>sincronizando y fusionando</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>esperando sincronización</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>servidor no conectado</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>autenticando en servidor</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>sincronización automática desactivada</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconocido</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Error de red</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>No se puede resolver la dirección del proxy</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>No se puede resolver la dirección del servidor</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>No se puede conectar al servidor</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Fallo al intentar establecer una conexión segura. Por favor verifique el certificado SSL del servidor</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>La transferencia de datos fue interrumpida. Por favor verifique la red o el firewall</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Se acabó el tiempo de espera para la transferencia de datos. Por favor verifique la red o el firewall</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Redireccionamiento http inesperado del servidor. Por favor verifique la configuración del servidor</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Error del servidor</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>No hay suficiente memoria</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>Fallo al escribir los datos en el cliente. Por favor verifique el espacio en disco y los permisos de las carpetas</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Espacio de almacenamiento completo</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Biblioteca eliminada en el servidor</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Biblioteca dañada en el servidor</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>El espacio de almacenamiento ha sido utilizado en su totalidad</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicializando...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>conectando al servidor...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexando archivos...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Descargando lista de archivos...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Descargando archivos...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Creando carpeta...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Agregando cambios en el archivo...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Listo</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>verificando informacion del servidor...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Cancelando</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Cancelado</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Error SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Error de red: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Error de servidor</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>fallo al abrir la base de datos de certificados</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>El archivo "%1" no existe en "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 no encontró una aplicación para abrir %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Biblioteca "%1" creada</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Biblioteca "%1" eliminada</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Renombrar %1 a</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>No es posible descargar el ítem "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>copiar falló</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Agregado</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Borrado</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Removido</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Modificado</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Renombrado</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Agregados o modificados</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Movido</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Carpeta agregada</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Carpeta removida</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Carpeta renombrada</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Carpeta movida</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>archivos</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>carpetas</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>y otros %1</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Biblioteca revertida al estado en</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Archivo "%1" revertido al estado en %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Carpeta borrada recuperada</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Nombre de biblioteca o descripción cambiados</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Auto fusionado por el sistema %1</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Ahora</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>hace 1 día</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>hace %1 días</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>hace 1 hora</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>hace %1 horas</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>hace 1 minuto</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>hace %1 minutos</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><No es Parte del Certificado></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Sincronizar esta biblioteca con:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Sincronizar esta carpeta con:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Carpeta</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Carpeta de sólo lectura</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Documento</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Documento PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Archivo de Imagen</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Documento de Texto</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Archivo de Audio</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Archivo de Video</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Documento de Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Documento de PowerPoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Documento de Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>La ruta "%1" está en conflicto con una ruta del sistema</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>La ruta "%1" está en conflicto con una biblioteca existente</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>subiendo lista de archivos</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>El archivo está bloqueado por otra aplicación</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>La carpeta está bloqueada por otra aplicación</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>El archivo está bloqueado por otro usuario</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>La ruta es inválida</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Error al indexar</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>La ruta finaliza con un punto o con un espacio</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>La ruta contiene caracteres inválidos como '|' or ':'</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>fallo al abrir el caché de la base de datos de archivos</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>El nombre de la biblioteca contiene caracteres inválidos, como ':', '*', '|', '?'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>Actialización de archivo denegada debido a configuración de permisos de la carpeta</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>El cliente %1 ya se está ejecutando</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>Datos internos corruptos en el cliente. Por favor intente resincronizar la biblioteca</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>No tiene permiso de escritura en la biblioteca</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>No tiene permiso para sincronizar esta carpeta</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>Todos los items eliminados de la papelera </translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>Todos los items con mas de %1 días eliminados de la papelera</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>Borrador publicado</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>Borrador creado</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>Archivo creado</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>Archivo renombrado</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>Borrador eliminado</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>Archivo eliminado</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>Archivo recuperado</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>Archivo movido</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>Archivo actualizado</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>Carpeta creada</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>Carpeta renombrada</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>Carpeta eliminada</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>Carpeta recuperada</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>Carpeta movida</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>Biblioteca creada</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>Biblioteca renombrada</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>Biblioteca eliminada</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>Biblioteca recuperada</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>Creado o actualizado un archivo en una biblioteca o carpeta sin permiso de escritura</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>Permiso denegado en el servidor</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>Actualizaciones concurrentes al archivo. El archivo es salvado como archivo de conflicto</translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>Una carpeta que podría contener archivos todavía no subidos es movida a la carpeta seafile-recycle-bin</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation>fallo al abrir la base de datos de id de errores de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>El archivo no existe</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Esta biblioteca aún no ha sido descargada</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Error:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>cada %1 segundos</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Icono del repositorio</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>NombreRepositorio</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Propietario:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Última modifiación:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Tamaño:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Ruta Local:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Estado:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Estado del Repositorio</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nombre:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Intervalo de Sincronización:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Esta biblioteca no ha sido descargada</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>No es posible abrir el archivo "%1" desde la biblioteca "%2", que no existe</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Actualizado Recientemente</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Mis bibliotecas</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sub Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Compartido conmigo</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Compartido con todos</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Compartido con grupos</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Bibliotecas Sincronizadas</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicializando sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactivar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Mostrar d&etalles</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Mostrar detalles de esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Sincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Sincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Actualizado Recientemente</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Sincronizar a&hora</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Sincronizar biblioteca inmediatamente</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancelar descarga</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Cancelar descarga de la biblioteca</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Abrir carpeta</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>abrir carpeta local</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>Abrir carpeta &local</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Desincronizar</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>desincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Ver en la nube</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>ver esta biblioteca en la web</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Compartir con un usuario</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Compartir esta biblioteca con un usuario</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Compartir con un grupo</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Compartir esta biblioteca con un grupo</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Abrir navegador de archivos</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>abrir esta biblioteca en el navegador de archivos incorporado</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>A&bandonar compartido</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>abandonar compartido</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Resincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>desincronizar y resincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Establecer &Intervalo de sincronización</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>establecer intervalo de sincronización para esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>¿Seguro que desea desincronizar la biblioteca "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>¿Seguro que desea resincronizar la biblioteca "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>¿Está seguro de sobreescribir el archivo "%1"?</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Fallo al desincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>¿Seguro que desea abandonar el compartido "%1"?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Abandonar compartido falló</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fallo al cancelar la tarea:
+
+.%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>La descarga fue cancelada</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>No tiene permiso para subir archivos a esta carpeta</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>No es posible sobreescribir el archivo "%1" con él mismo</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>No se puede eliminar el archivo "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Fallo al subir el archivo: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Intervalo de Sincronización (en segundos):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Establecer Intervalo de Sincronización para la Biblioteca "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Buscar bibliotecas</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Fallo al obtener información de las bibliotecas<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation>Aviso: el certificado ssl de este servidor no es de confianza, proceder de todos modos?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Fallo al crear registro: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>fallo al guardar el id del cliente</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>fallo al acceder a %1</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>Id del cliente incorrecto</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>fallo al leer %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>Enlace Interno %1</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar al portapapeles</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>Enlace interno %1:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>%1 Desktop Access Link:</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>error interno: fallo al conectar con el servicio</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desactivar auto sincronización</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activar auto sincronización</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Cerrar</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Ventana principal</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Configuración</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Abrir &carpeta %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>abrir carpeta %1</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Abrir &registros</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Mostrar errores al sincronizar archivos</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>Acerca &de</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Muestra la información de la aplicación</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Ayuda en línea</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Archivo</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>auto sincronización desactivada</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Subiendo</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Descargando</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>abrir registros %1</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>abrir ayuda en línea %1</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>algunos servidores no contectados</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Subir archivos de registros</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>subir %1 archivos de registros</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Por favor, primero ingrese</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>Reparar extensión explorer</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>Iconos de estado de sincronización para Explorer reparados con éxito</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>Fallo al reparar iconos de estado de sincronización para Explorer</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>tiene algún error de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Mostrar en carpeta</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostrar en carpeta</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Buscar archivos</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Fallo al buscar<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Estado de conexión de servidores</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>conectado</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>desconectado</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Cerrar</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Por favor suministre la contraseña para la biblioteca</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Suministre la contraseña para la biblioteca %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Ingrese la contraseña</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Contraseña incorrecta</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Error desconocido</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Configuración</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Iniciar automáticamente %1 después del inicio de sesión</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Ocultar el icono de %1 de la barra</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Ninguno</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>Proxy HTTP</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Proxy Socks5</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Proxy del Sistema</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Ha cambiado el idioma. ¿Desea reiniciar para aplicar el cambio?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>La dirección del proxy no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>El puerto del proxy es incorrecto</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>El nombre de usuario del proxy no puede estar vacío</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>La contraseña del proxy no puede estar vacía</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Ocultar ventana principal al iniciar</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Notificar al sincronizar bibliotecas</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Habilitar la sincronización de archivos temporarios de MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Límite de velocidad de descarga (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Límite de velocidad de subida (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Básico</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>No desincronizar automáticamente una biblioteca</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>No desincronizar automáticamente una biblioteca cuando la carpeta local haya sido removida o no esté accesible por otros motivos.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>No desincronizar una biblioteca cuando no se encuentre en el servidor</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>No desincronizar automáticamente una biblioteca cuando no se encuentre en el servidor</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Habilitar extensión FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Habilitar extensión Explorer</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Verificar si hay actualizaciones automáticamente</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>No verificar el certificado del servidor en sincronización HTTPS</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Habilitar sincronización con una carpeta existente con distinto nombre</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Avanzado</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Idioma (requiere reinicio)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Idioma</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Tipo de Proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Dirección:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Puerto:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Usuario:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Contraseña:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>El servidor proxy requiere una contraseña</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Red</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lectura Escritura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Eliminar Compartido</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Click para editar</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Creado por %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lectura Escritura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Sólo Lectura</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Grupo</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Usuario</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Permiso</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>La operación anterior todavía está en curso</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Enlace para Compartir</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Enlace para compartir:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Descarga Directa</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar al portapapeles</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation>Enlace de Subida</translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation>Enlace de subida:</translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Conexión no confiable</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 utiliza un certificado de seguridad inválido. La conexión podría no ser segura. Desea continuar?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>La huella digital de la clave RSA actual es %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>La huella digital de la clave RSA anterior es %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Recordar mi elección</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Abrir este archivo</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>ver en la &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>ver este archivo en el sitio web</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>reintentar</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Fallo al obtener información de archivos favoritos<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Aún no tiene archivos favoritos.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Errores al Sincronizar Archivos</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>No hay errores de sincronización</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Doble click para abrir la biblioteca</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ruta</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Error</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Hora</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Ingrese el identificador de autenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Auenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Por favor ingrese el identificador de autenticación de dos factores</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Recordar este dispositivo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Desinstalar %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>¿Seguro que desea eliminar la información de la cuenta %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Eliminando información de la cuenta...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Detalles</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>texto</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="et_EE" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>close</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>delete</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="fr_FR" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>À propos %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Client %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> RÉV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>À propos</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Vérification des mises à jour</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>Impossible d'ouvrir la base de données des comptes</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Autorisation expirée, reconnectez-vous</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Impossible de supprimer les jetons de synchronisation des dépôts locaux : %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Impossible de synchroniser le dépôt depuis le serveur : %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Paramètres du compte</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Entrez l'adresse du serveur</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 n'est pas une adresse de serveur valide</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Impossible de sauvegarder les informations du compte</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Impossible de sauvegarder les changements : %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Information du compte mise à jour avec succès</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Adresse du serveur</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-mail</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>Êtes-vous certain de vouloir supprimer le compte %1?<br><br> Le compte sera supprimé localement. Toute la configuration de synchronisation sera également supprimée. Le compte sur le serveur ne sera pas affecté.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Impossible de désynchroniser les bibliothèques de ce compte:%1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>Cliquez pour ouvrir le site web</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>Version pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Pas de compte</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Sélectionner</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Paramètres du compte</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Connexion</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Supprimer</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Ajouter un compte</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Déconnexion</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>Non connecté</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulaire</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Compte</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>E-mail</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>Serveur</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Les activités sur les fichiers sont supportées uniquement dans la version professionnelle %1 .</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>Réessayer </translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Impossible de récupérer les informations des activités. Veuillez %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Envoyé avec succès</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Le fichier "%1"
+a été envoyé avec succès.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Le fichier "%1"
+n'a pu être envoyé.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Erreur de permission !</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorisation expirée</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Le fichier n'existe pas</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>Le fichier est verrouillé par %1, veuillez réessayer plus tard</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Échec de l'envoi : %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Impossible de créer le dossier des avatars</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Vérification de permission</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Tâches de téléchargement</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>Supprimer toutes les tâches terminées avec succès</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Pas de tâches de téléchargement en cours.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Vider</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fermer</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Bibliothèque</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Répertoire</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Annuler cette tâche</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>Annuler cette tâche</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Supprimer cette tâche</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Impossible d'annuler cette tâche :
+
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Impossible de supprimer cette tâche :
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Réduire</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fermer</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliothèques</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favoris</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Activités</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Rechercher</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>Vitesse actuelle de téléchargement</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>Vitesse actuelle d'envoi</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Veuillez choisir un dossier à synchroniser</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>Aucun serveur connecté</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>Tous les serveurs sont connectés</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Des serveurs ne sont pas connectés</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulaire</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>Réduire</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>Fermer</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Sélectionnez </translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>Marque</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>ou déposez un dossier à synchroniser</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>Vitesse de téléchargement</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>flèche du bas</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>Vitesse d'envoi</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>flèche du haut</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Erreur lors de la création de la configuration de ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Impossible de créer la bibliothèque pré-configurée "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>impossible de lire %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Créer une bibliothèque</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Veuillez choisir un répertoire</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Création...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Impossible de générer une clé de cryptage pour cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Veuillez choisir le répertoire à synchroniser</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Le dossier %1 n'existe pas</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Veuillez entrer un nom</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Veuillez entrer un mot de passe</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Les mots de passe ne correspondent pas</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Impossible d'ajouter la tâche de téléchargement :
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Impossible de créer la bibliothèque sur le serveur :
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Répertoire :</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Choisir</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nom :</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>Chiffré</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Mot de passe :</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Vérification du mot de passe :</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>Texte d'état</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>Le client %1 n'a pas pu s'initialiser</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 a quitté de manière inattendue</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Veuillez entrer un mot de passe</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Synchroniser la bibliothèque "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Synchroniser le répertoire "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Synchroniser avec le dossier</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ou</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>Synchroniser avec un dossier existant</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation> Créer un nouveau dossier à synchroniser</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Synchroniser avec un dossier existant :</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Choisissez un dossier</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Le dossier n'existe pas</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Choisissez le dossier à synchroniser.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Votre organisation a empêché l'enregistrement d'une bibliothèque en dehors du dossier %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Conflit avec le fichier existant "%1", choisissez un dossier différent.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Conflit avec la bibliothèque existante "%1", choisissez un dossier différent.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Le dossier "%1" existe déjà. Êtes-vous certain de vouloir le synchroniser (son contenu sera fusionné) ?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Cliquez sur Non pour synchroniser avec un nouveau dossier</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Impossible de trouver un autre nom de dossier</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Impossible d'ajouter la tâche de téléchargement :
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Impossible de télécharger les informations du dépôt :
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Télécharger la bibliothèque</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>Choisir...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Mot de passe de cette bibliothèque :</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Détail des modifications</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Fichiers ajoutés</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Fichiers supprimés</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Fichiers modifiés</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Dossiers ajoutés</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Dossiers supprimés</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Ouvrir</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Ouvrir le dossier &parent</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Navigateur de fichiers</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Retour</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Avancer</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Dossier personnel</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Envoyer des fichiers</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Envoyer un répertoire</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Vous n'avez pas les droits pour envoyer des fichiers dans cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Créer un dossier</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Rafraichir</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 éléments</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Nom du dossier</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Nom de dossier invalide</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Le nom "%1" est déjà utilisé.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>Réessayer </translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Impossible de récupérer les informations des fichiers <br/>Veuillez %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Le dossier est vide.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Entrer le nom du fichier à enregistrer...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Impossible d'effacer le fichier "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Entrez le chemin du répertoire d'enregistrement...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Voulez-vous écraser le fichier existant "%1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Le fichier "%1" n'a pas été synchronisé</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Le fichier %1 existe déjà.<br/>Voulez-vous le remplacer?<br/><small>(Choisissez Non pour l'enregistrer avec un autre nom).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Le fichier n'existe pas</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Impossible de télécharger le fichier : %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Sélectionner un fichier à envoyer</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Sélectionner un répertoire à envoyer</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Renommer</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Voulez-vous vraiment supprimer ces éléments ?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Échec de la création du dossier</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Échec du verrouillage du fichier </translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Sélectionner un fichier à mettre à jour %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Échec du renommage</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Échec d'effacement</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Échec du partage</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Impossible de coller les fichiers d'un même dossier</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>Ce dossier ne peut pas être collé dans son sous-dossier</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Échec de la copie</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Échec du déplacement</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Échec de création de la bibliothèque</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Vous n'avez pas la permission d'envoyer ce répertoire</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorisation expirée</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Erreur de permission !</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Bibliothèque/Répertoire non trouvé.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Échec de l'envoi du fichier %1 : %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>Impossible de créer le dossier de cache</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>Impossible d'ouvrir le dossier de cache</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Rechercher des fichiers</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Impossible d'obtenir le lien</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>Impossible d'obtenir les informations du lien d'envoi du fichier "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>En attente</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Envoyer</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Envoi vers %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Télécharger</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Téléchargement de %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 sur %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Échec de l'envoi du fichier "%1", voulez-vous réessayer ?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Réessayer </translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Passer</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Enregistrement</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Échec de l'enregistrement du fichier</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>Erreur %1 de la requête de progression d'index</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Nom</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Taille</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Dernière modification</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Afficher dans le dossier</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Afficher dans le dossier</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Opération annulée</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>En attente</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>Tâche annulée</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Erreur interne du serveur</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Le quota de stockage a été atteint</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>Verrouillé par %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nom</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Taille</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Dernière modification</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>Modificateur</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Enregistrer sous...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Verrouiller</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Renommer</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Supprimer</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Partager avec un groupe</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Mise à jour</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Copier</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Cou&per</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Coller</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Annul&er le téléchargement</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Synchroniser ce dossier</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Cette fonctionnalité est disponible uniquement dans la version professionnelle
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Générer un lien de téléchargement</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Partager avec un utilisateur</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>G&énérer %1 lien interne</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Enregistrer sous...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Dé&verrouiller</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Impossible de supprimer des fichiers en lecture seule</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Impossible de couper des fichiers en lecture seule</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Réessayer l'envoi</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Supprimer la version locale</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Enregistrer la version locale sous ...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Ouvrir le dossier du cache local</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation>&Générer %1 un lien d'envoi</translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Impossible d'obtenir le lien</translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation>Le fichier "%1" est verrouillé par %2</translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation>Impossible d'obtenir l'information de verrouillage du fichier "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation>Impossible d'obtenir le lien d'envoi du fichier "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Impossible de créer des dossiers</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Impossible de créer des fichiers temporaires</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Impossible d'écrire un fichier sur le disque</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Impossible de supprimer une ancienne version du fichier téléchargé</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Impossible de déplacer le fichier</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>Initialisation de %1</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Choisissez %1 dossier</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Veuillez choisir un répertoire</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>L'initialisation n'est pas terminée. Voulez-vous réellement quitter?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Le dossier %1 n'existe pas</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Choisissez un dossier</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Veuillez choisir un dossier. Un %1 sous dossier y sera créé. Quand vous téléchargez une bibliothèque , elle y sera sauvegardée par défaut.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Choisir...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Suivant</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organise les fichiers par bibliothèques.
+Voulez-vous télécharger la bibliothèque par défaut ?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Vérification de votre bibliothèque par défaut...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Création de la bibliothèque par défaut</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Impossible de créer la bibliothèque par défaut :
+
+La version de votre serveur doit être 2.1 ou plus.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Impossible de récupérer la bibliothèque par défaut :
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Impossible de créer la bibliothèque par défaut :
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Téléchargement de la bibliothèque par défaut...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Impossible de télécharger la bibliothèque par défaut :
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>La bibliothèque par défaut a été téléchargée.
+Vous pouvez cliquer sur le bouton "Ouvrir" pour la voir.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Erreur lors du téléchargement de la bibliothèque par défaut : %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Impossible de télécharger la bibliothèque par défaut :
+ %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organise les fichiers par bibliothèques.
+Voulez-vous télécharger la bibliothèque par défaut ?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Passer</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Lancer en arrière plan</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Ouvrir</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Terminer</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Télécharger la bibliothèque par défaut</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Oui</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>Charger plus</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>L'envoi des fichiers log a échoué</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Envoi des fichiers log</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Erreur de permissions !</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Bibliothèque/Répertoire non trouvé.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorisation expirée</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>L'envoi des fichiers log a échoué : %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Envoi des fichiers log réussi</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Compression</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 sur %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Ajouter un compte</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Authentification unique</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Reconnexion</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Connexion...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Erreur réseau : %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Attention :</b> Le certificat de sécurité de ce serveur n'est pas approuvé, continuer quand même ?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Veuillez entrer l'adresse du serveur</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 n'est pas une adresse de serveur valide</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Veuillez entrer le nom d'utilisateur</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Veuillez entrer le nom de l'ordinateur</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 adresse serveur</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>L'adresse du serveur ne peut être vide</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 n'est pas une adresse de serveur valide. Cela doit commencer par 'https://'</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Veuillez entrer le mot de passe</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>E-mail ou mot de passe incorrect</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Connexions trop fréquentes, veuillez attendre une minute</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Erreur interne du serveur</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Impossible de se connecter:%1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Impossible de se connecter</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Serveur :</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Par exemple : https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>ou http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Mot de passe :</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>Texte d'état</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Nom de l'ordinateur :</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>E-mail / Nom d'utilisateur </translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>Par exemple : portable de Julien</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Connexion</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Connexion automatique</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Vous êtes déconnecté. S'il vous plait</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>Connexion</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Ajouter un compte</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Rafraîchir</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>"%1"est synchronisé</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Fichiers chargés sur "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>Impossible de synchroniser le fichier %1
+Le fichier est verrouillé par une autre application. Ce fichier sera mis à jour lorsque vous aurez fermé l'application.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>Impossible de synchroniser le dossier %1
+Le dossier est verrouillé par une autre application. Ce dossier sera mis à jour lorsque vous aurez fermé l'application.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>Impossible de synchroniser le fichier %1
+Le fichier est verrouillé par un autre utilisateur. La mise à jour de ce fichier n'est pas chargée.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>Impossible d'indexer le fichier %1
+Veuillez vérifier les permissions sur le fichier et l'espace disque.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>Impossible de synchroniser %1
+Le fichier se termine par un espace ou un autre caractère invalide et ne peut pas être enregistré sur Windows</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>Impossible de synchroniser %1
+Le nom de fichier contient des caractères invalides. Il n'est pas synchronisé sur cet appareil.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>La mise à jour de %1 est refusée par les paramètres de permissions du dossier.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>Pas de permission pour synchroniser le dossier %1.</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation>Les mises à jour dans la bibliothèque en lecture seule %1 ne seront pas envoyées.</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation>Mises à jour simultanées du fichier. Le fichier %1 est enregistré en tant que fichier de conflit.</translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation>Le dossier %1 est déplacé dans le dossier seafile-recycle-bin car il contient des fichiers qui n'ont pas encore été chargés.</translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation>Le dossier de la bibliothèque %1 a été supprimé ou déplacé. La bibliothèque n'est pas synchronisée.</translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Partager %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Entrez le nom du groupe</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Entrez un nom d'utilisateur ou une adresse e-mail</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Mise à jour réussie</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>Échec de l'opération de partage : %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Suppression réussie</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Impossible d'obtenir les informations de partage du dossier</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Impossible de récupérer vos informations de groupe et de contact</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Veuillez entrer le nom d'utilisateur</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Veuillez entrez le nom du groupe</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Groupe "%1" inexistant</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Déjà partagée avec le groupe %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Déjà partagée avec l'utilisateur %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>L'opération précédente est encore en cours</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Partager avec :</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Partager</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Droit d'accès :</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lecture-Écriture</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Lecture seule</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fermer</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>Synchronisé</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>Indexation des fichiers</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Initialisation de la synchronisation</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>Téléchargement</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>Envoi</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>Fusion de la synchronisation</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>En attente de synchronisation</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>Serveur non connecté</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>Authentification du serveur</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>La synchronisation automatique est désactivée</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>Inconnu</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Erreur réseau</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>L'adresse du proxy ne peut être atteinte</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>L'adresse du serveur ne peut être atteinte</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Impossible de se connecter au serveur</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Impossible d'établir une connexion sécurisée. Veuillez vérifier votre certificat SSL</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>Le transfert de données a été interrompu. Veuillez vérifier le connexion ou le pare-feu.</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Le transfert des données a expiré. Veuillez vérifiez le réseau ou le pare-feu</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Redirection HTTP non gérée depuis le serveur. Veuillez vérifier la configuration du serveur</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Erreur serveur</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Pas assez de mémoire</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>Impossible d'écrire les données sur le client. Veuillez vérifier l'espace disque ou les permissions du dossier.</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Le quota de stockage est atteint</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Bibliothèque supprimée sur le serveur</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Bibliothèque endommagée sur le serveur</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Le quota de stockage est atteint</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Initialisation...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>Connexion au serveur...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>Indexation des fichiers...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Téléchargement de la liste des fichiers en cours ...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Téléchargement des fichiers en cours ...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Création du dossier ...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Fusion des changements des fichiers...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Terminé</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>vérification des informations du serveur...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Annulation</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Annulé</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Erreur SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Erreur réseau : %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Erreur du serveur</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>Échec d'ouverture de la base des certificats</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Le fichier "%1" n'existe pas dans "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 ne trouve pas d'application pour ouvrir le fichier %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Bibliothèque "%1" créée</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Bibliothèque "%1" supprimée</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Renommer %1 en </translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Impossible de télécharger l'objet "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>Échec de la copie</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Modification de</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Suppression de</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Suppression de</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Modification de</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Renommage de</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Ajouté ou modifié</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Déplacement de</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Répertoire ajouté</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Répertoire supprimé</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Répertoire renommé</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Répertoire déplacé</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>Fichiers</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>Répertoires</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>ainsi que %1</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Retour de la bibliothèque à l'état du</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Retour du fichier %1 à l'état du %2</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Restauration de la bibliothèque effacée</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Changement de nom ou de description de la bibliothèque</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Fusion automatique par %1 système</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>À l'instant</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>Il y a un jour</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>Il y a %1 jours</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>Il y a 1 heure</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>Il y a %1 heures</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>Il y a 1 minute</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>Il y a %1 minutes</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Synchroniser cette bibliothèque avec :</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Synchroniser ce dossier avec :</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Dossier</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Dossier en lecture seule</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Document</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Document PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Fichier image</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Document texte</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Fichier audio</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Fichier vidéo</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Document Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Document PowerPoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Document Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Le chemin "%1" est en conflit avec un chemin système</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Le chemin "%1" est en conflit avec une bibliothèque existante</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>envoi de la liste des fichiers</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>Le fichier est verrouillé par une autre application</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>Le dossier est verrouillé par une autre application</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>Le fichier est verrouillé par un autre utilisateur</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Le chemin n'est pas valide</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Erreur lors de l'indexation</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>Le chemin se termine par un espace ou un caractère de période</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>Le chemin contient des caractères non valides comme '|' ou ':' </translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>Échec de l'ouverture du fichier cache de la base de données</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>La bibliothèque contient des caractères invalides comme ':', '*', '|', '?'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>La mise à jour du fichier est impossible à cause des paramètres de permission du dossier.</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>Le client %1 est déjà démarré.</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>Données internes corrompues sur le client. Veuillez essayer de resynchroniser la bibliothèque</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>Vous n'avez pas les droits pour écrire dans cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>Vous n'avez pas la permission de synchroniser ce dossier.</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>Suppression de tous les éléments de la corbeille</translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>Suppression des éléments âgés de plus %1 jours de la corbeille</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>Brouillon publié</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>Brouillon créé</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>Fichier créé</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>Fichier renommé</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>Brouillon supprimé</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>Fichier supprimé</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>Fichier restauré</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>Fichier déplacé</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>Fichier mis à jour</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>Dossier créé</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>Dossier renommé</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>Dossier supprimé</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>Dossier restauré</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>Dossier déplacé</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>Bibliothèque créée</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>Bibliothèque renommée</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>Bibliothèque supprimée</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>Bibliothèque restaurée</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>Fichier créé ou mis à jour dans une bibliothèque ou un dossier non inscriptible.</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>Permission refusée sur le serveur</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>Mises à jour simultanées du fichier. Le fichier est sauvegardé en tant que fichier de conflit.</translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>Un dossier qui peut contenir des fichiers qui ne sont pas encore téléchargés est déplacé dans le dossier seafile-recycle-bin.</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>Le fichier n'existe pas</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Bibliothèque "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Cette bibliothèque n'a pas encore été téléchargée</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Erreur : </translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>Chaque %1 secondes</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>IcôneDépôt</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>NomDépôt</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>LabelTexte</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Propriétaire :</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Dernière modification :</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Taille :</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Répertoire local :</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>État :</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>EtatDépôt</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nom :</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Intervalle de synchro : </translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fermer</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Cette bibliothèque n'a pas été téléchargée</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Impossible d'ouvrir le fichier "%1" dans la bibliothèque inexistante "%2"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Bibliothèques mises à jour récemment</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Mes bibliothèques</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sous-bibliothèques</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Bibliothèques partagées avec moi</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Bibliothèques partagées avec tous</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Bibliothèques partagées avec des groupes</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Bibliothèques synchronisées</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Initialisation de la synchronisation</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Désactiver la synchronisation automatique</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activer la synchronisation automatique</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Afficher les &détails</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Afficher les détails de cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Synchroniser cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Synchroniser cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Récemment envoyés</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Synchroniser &maintenant</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Synchroniser cette bibliothèque immédiatement</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Annuler le téléchargement</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Annuler le téléchargement de cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Ouvrir le dossier</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>Ouvrir le dossier local</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>&Ouvre un dossier local</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Désynchroniser</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Désynchroniser cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>Voir dans le &cloud</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>Voir cette bibliothèque sur Seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Partager avec l'utilisateur</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Partager cette bibliothèque avec un utilisateur</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Partager avec un groupe</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Partager cette bibliothèque avec un groupe</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Ouvrir l'explorateur de fichiers du cloud</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>Ouvrir cette bibliothèque dans l'explorateur de fichiers du cloud</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>&Quitter le partage</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>Quitter le partage</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Resynchroniser cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>Désynchroniser et resynchroniser cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Paramétrer l'&intervalle de synchro</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>Paramétrer l'intervalle de synchronisation pour cette bibliothèque</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>Êtes-vous certain de vouloir désynchroniser la bibliothèque "%1" ?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>Êtes-vous certain de vouloir resynchroniser la bibliothèque "%1" ?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>Êtes-vous certain de vouloir remplacer le fichier "%1" ?</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Impossible de désynchroniser la bibliothèque "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>Êtes-vous certain de vouloir quitter le partage "%1" ?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Échec d'abandon du partage</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Impossible d'annuler cette tâche :
+
+ %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Le téléchargement a été annulé</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Vous n'avez pas la permission d'envoyer ce répertoire</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Impossible d'écraser le fichier %1 avec lui-même</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Impossible de supprimer le fichier "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Échec de l'envoi du fichier : %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Intervalle de synchro (en secondes) :</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Paramétrer l'intervalle de synchro pour la bibliothèque "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Rechercher des bibliothèques</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>Réessayer </translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Impossible de récupérer les informations des bibliothèques<br/>Veuillez %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Attention :</b> Le certificat de sécurité de ce serveur n'est pas approuvé, continuer quand même ?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Échec de l'initialisation du log: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Oui</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Non</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>Impossible de sauvegarder l'id du client.</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>Impossible d'accéder à %1.</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>Id de client incorrect.</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>Impossible de lire %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 lien interne</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copier dans le presse-papiers</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>Lien interne %1</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>%1 Lien d'accès au bureau :</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erreur Inconnue</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>Erreur interne : impossible de se connecter au processus.</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Désactiver la synchronisation automatique</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Activer la synchronisation automatique</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Quitter</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Ouvrir la fenêtre principale</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Paramètres</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Ouvrir le &dossier %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>Ouvrir le dossier %1</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Ouvrir le dossier &logs</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Ouvrir le log des erreurs de synchronisation</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&À propos</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Voir la boite de dialogue À propos</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>Aide en &Ligne</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Fichier</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>La synchronisation automatique est désactivée</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Envoi en cours</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Téléhargement en cours</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>Ouvrir le dossier de log %1</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>Ouvrir l'aide en ligne de %1</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Des serveurs ne sont pas connectés</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Envoi des fichiers log</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>Envoi %1 des fichier de log</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Veuillez vous connecter d'abord</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>Réparer l'extension de l'explorateur de fichiers</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>Succès de la réparation des icônes de statut de synchronisation de l'extension de l'explorateur de fichier</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>Echec de réparation des icônes de statut de synchronisation de l'extension de l'explorateur de fichier</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>Il y a une erreur de synchromisation</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Afficher dans le dossier</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Afficher dans le dossier</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Recherche fichiers</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>Réessayer </translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Impossible de rechercher<br/>Veuillez %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>État de connexion des serveurs</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>Connecté</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>Déconnecté</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fermer</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Veuillez entrer le mot de passe de la bibliothèque</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Veuillez entrer le mot de passe de la bibliothèque %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Veuillez entrer le mot de passe</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Mot de passe incorrect</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erreur inconnue</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Paramètres</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Démarrer automatiquement %1 à l'ouverture de session utilisateur</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Masquer l'icône de %1 de la barre</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Aucun</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>Proxy HTTP</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Proxy Socks5</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Utiliser les paramètres proxy du système</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Vous avez changé de langue, redémarrer pour appliquer ?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>L'adresse du serveur proxy ne peut être vide</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Le port proxy est erroné</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>Le nom d'utilisateur du proxy ne peut être vide</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>Le mot de passe du proxy ne peut être vide</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Cacher la fenêtre principale au démarrage </translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Signaler lorsque les bibliothèques sont synchronisées</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Activer la synchronisation des fichiers temporaires MSOffice/LibreOffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Vitesse de téléchargement maximum (Ko/s) :</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Vitesse d'envoi maximum (Ko/s) :</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Basique</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Ne pas désynchroniser automatiquement une bibliothèque</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Ne pas désynchroniser automatiquement une bibliothèque quand le dossier local est supprimé ou inaccessible pour d'autres raisons</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Ne pas désynchroniser une bibliothèque non trouvée sur le serveur</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Ne pas désynchroniser automatiquement une bibliothèque quand elle n'est pas trouvée sur le serveur</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Activer l'extension FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Activer l'extension de l'explorateur de fichiers</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Vérifier les mises à jour automatiquement</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Ne pas vérifier le certificat serveur lors de la connexion HTTPS</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Autoriser la synchronisation avec un dossier portant un nom différent</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Avancé</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Langue (redémarrage nécessaire)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Langue</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Type de proxy :</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Serveur :</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Port :</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Identifiant :</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Mot de passe :</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Le serveur proxy requiert un mot de passe</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Réseau</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lecture et Écriture</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Lecture seule</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Supprimer le partage</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Cliquez pour éditer</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Créée par %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lecture Écriture</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Lecture seule</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Groupe</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Utilisateur</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Droit d'accès</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>L'opération précédente est toujours en cours</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Lien de partage</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Lien de partage :</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Téléchargement direct</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copier dans le presse-papiers</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Connexion non certifiée</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 utilise un certificat de sécurité invalide. La connexion peut ne pas être sécurisée. Voulez-vous continuer ?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>L'empreinte courante de la clé RSA est %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>L'empreinte précédente de la clé RSA est %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Se souvenir de mon choix</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Oui</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Non</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Ouvrir</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Ouvrir ce fichier</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>Voir sur &Internet</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>Voir ce fichier sur le site web</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>Réessayer </translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Impossible de récupérer les informations des fichiers favoris<br/>Veuillez %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Vous n'avez pas de fichiers favoris pour l'instant.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Fichier d'erreurs de synchronisation</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Aucune erreur de synchronisation</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Double-clic pour ouvrir une bibliothèque</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Bibliothèque</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Chemin</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Erreur</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Temps</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Entrer le jeton d'authentification double facteur</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Authentification double facteur</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Veuillez entrer le jeton d'authentification double facteur</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Fenêtre de dialogue</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Se souvenir de cet appareil</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuler</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Désinstallation de %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Voulez vous supprimer les informations du compte %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Suppression des informations du compte...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialogue</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>Texte</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Oui</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Non</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="he_IL" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>נכשל בפתיחת מסד הנתונים של חשבונות</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>משימות להורדה</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>להסיר את כל המשימות המוצלחות</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>אין משימות להורדה עכשיו.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>לפנות</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>לסגור</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>ספרייה</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>נתיב</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>בטל משימה זו</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>בטל משימה זו</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>הסר משימה זו</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>נכשל ניסיון ביטול משימה זו:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>נכשל ניסיון להסיר משימה זו:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>לצמצם</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>סגור</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>קצב הורדה הנוכחי</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>קצב העלאה הנוכחי</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>אנא בחר תיקייה לסנכרן</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>שום שרת מחובר</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>כל השרתים מחוברים</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>חלק מהשרתים אינם מחוברים</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>טופס</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>לוגו</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>לצמצם</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>סגור</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>בחר</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>או שחרר תיקייה כדי לסנכרן</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>קצב הורדה</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>חץ למטה</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>קצב העלאה</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>חץ למעלה</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>שגיאה בעת יצירת תצורת ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>נכשל בקריאה 1%</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>ליצור ספרייה</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>אנא בחר ספרייה</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>יוצר...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>נא לבחור את הספרייה כדי לסנכרן</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>התיקייה %1 אינה קיימת</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>אנא הכנס את השם</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>אנא הכנס את הסיסמה</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>סיסמאות אינן תואמות</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>שגיאה לא ידועה</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>נכשל ניסיון להוסיף משימה להורדה:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>נתיב:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>בחר</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>שם:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>מוצפן</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>סיסמא:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>סיסמא שוב:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation> תיאור מצב</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ביטול</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>אנא הכנס את הסיסמה</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>סנכרון ספריית "1%"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>נכשל ניסיון להוסיף משימה להורדה:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>הורד ספרייה</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>בחר...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>סיסמא לספרייה זו:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ביטול</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>אתחול %1</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>אנא בחר ספרייה</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>אתחול לא הושלם. לפרוש בכל מקרה?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>התיקייה %1 אינה קיימת</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>לוגו</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>בחר...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>הבא</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ביטול</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>בדיקת ספריית ברירת המחדל שלך...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>יצירת ספריית ברירת מחדל...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>נכשל ביצירת ספריית ברירת מחדל:
+
+גרסת השרת חייבת להיות 2.1 או גבוה כדי לתמוך בזה.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>מוריד ספריית ברירת מחדל...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>ספריית ברירת המחדל הורד.
+אתה יכול ללחוץ על הכפתור "פתח" כדי לצפות בו.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>שגיאה בעת הורדת ספריית ברירת המחדל: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>נכשל בניסיון להוריד ספריית ברירת מחדל:
+ %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>דלג</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>הפעל ברקע</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>פתח</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>סיים</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>הורד את ספריית ברירת המחדל</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>כן</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>לוגו</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>הוסף חשבון</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>התחברות</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>שגיאת רשת:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>אזהרה:</ b> תעודת SSL של שרת זה אינה מהימנה, להמשיך בכל זאת?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>אנא הכנס את כתובת השרת</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 אינו כתובת שרת חוקית</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>אנא הכנס את שם המשתמש</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>אנא הכנס את הסיסמה</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>דוא"ל או סיסמא שגוי</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>שגיאה פנימית בשרת</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>נכשל בהתחברות: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>נכשל בהתחברות</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>לוגו</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>סיסמא:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation> תיאור מצב</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>התחבר</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ביטול</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>רענן</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>מסונכרן</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>יצירת אינדקס של הקבצים</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>אתחול הסינכרון</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>הורדה</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>מעלאה</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>מיזוג סנכרון</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>מחכה לסנכרון</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>שרת אינו מחובר</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>מאמת שרת</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>סינכרון אוטומטי כבוי</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>לא ידועה</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>אתחול...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>מתחבר השרת...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>יצירת אינדקס של הקבצים</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>יצירת תיקייה...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>למזג את השינויים בקובץ...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>נשלם</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>מבטל</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>בוטל</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>ספרייה "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>ספרייה זו עדיין לא הורדה</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>שגיאה:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>סמל מאגר</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>שם מאגר</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>תוויתטקסט</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>בעל:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>שונה לאחרונה:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>גודל:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>נתיב מקומי:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>מצב:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation> מצב המאגר</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>שם:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>לסגור</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>ספרייה זו לא בוצעה הורדה</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>עודכן לאחרונה</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>הספריות שלי</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>תת ספריות</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>להשבית סנכרון אוטומטי</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>אפשר סנכרון האוטומטי</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>לסנכרן את הספרייה זו באופן מיידי</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>ביטול הורדה</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>ביטול הורדה של ספרייה זו</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&פתח את תיקייה</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>לפתוח את התיקייה מקומית</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>ביטול &סינכרון</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>נתק מסינכרן ספרייה זו</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&הצג בא ענן</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>להציג ספרייה זו ב-seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>נתק מסינכרן ספרייה זו</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>נכשל ניסיון ביטול משימה זו:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>ההורדה בוטלה</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>שגיאה לא ידועה</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>להשבית סנכרון אוטומטי</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>אפשר סנכרון האוטומטי</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>צא</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>הצג חלון ראשי</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>הגדרות</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&אודות</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>הצג תיבת אודות של היישום</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>עזרה &באינטרנט</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>סנכרון אוטומטי הינו מושבת</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>חלק מהשרתים אינם מחוברים</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>מצב חיבור שרתים</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>מחובר</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>מנותק</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>לסגור</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>הגדרות</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>הסתר חלון ראשי בתחילה</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>הצג הודעה כאשר ספריות מסונכרנות</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>מגבלת מהירות ההורדה (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>מגבלת מהירות ההעלאה (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>ביטול</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>הסרת התקנה של 1%</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>האם אתה רוצה להסיר את פרטי חשבון של 1%?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>הסרת פרטי חשבון...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>דיאלוג</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>טקסט</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>כן</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>לא</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="hu_HU" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Információk a %1-ról</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Kliens %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>&Névjegy</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Frissítések keresése</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>A felhasználói adatbázis megnyitása nem sikerült</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Az autentikáció lejárt, jelentkezzen be újra</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Fiókbeállítások</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Kérem, adja meg a szerver címét</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>Érvénytelen kiszolgálócím: %1</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>A fiókinformációk mentése sikertelen</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>A módosítások mentése nem sikerült: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>A fiókbeállítások frissítése sikerült</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Szerver címe</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-mail</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>Biztos, hogy törli a fiókot: %1? <br><br>A fiók helyileg törlésre került. Minden szinkronizációs beállítás szintén törlésre kerül. A szerveren lévő fiók nem érintett a változásban.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>A kötetek szinkronizálásának megszüntetése nem sikerült: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>Kattintson a weboldal megnyitásához</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>pro verzió</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Nincs felhasználói fiók beállítva</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Válasszon</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Fiókbeállítások</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Bejelentkezés</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Töröl</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Fiók hozzáadása</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Kijelentkezés</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>nincs bejelentkezve</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Űrlap</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Fiók</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>E-mail</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>Szerver</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>A fájltevékenységek funkció csak %1 Server Professional Edition-ben érhető el.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>Újra</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Nem sikerült lekérdezni a fájl tevékenységeket. Kérem, %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>A feltöltés sikeres</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Fájl "%1"
+feltöltése sikeres.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Fájl "%1"
+feltöltése nem sikerült.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Az "avatars" könyvtárat nem sikerült létrehozni</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Jogosultságok ellenőrzése</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégse</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Letöltési feladatok</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>Végrehajtott feladatok eltávolítása</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Jelenleg nincsenek letöltési feladatok.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Törlés</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Bezárás</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Kötet</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Útvonal</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Feladat megszakítása</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>Feladat megszakítása</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Feladat eltávolítása</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>A feladat megszakítása nem sikerült:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>A feladat eltávolítása nem sikerült:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Kis méret</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Bezárás</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Kötetek</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Kedvencek</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Tevékenységek</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Keres</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>Aktuális letöltési sebesség</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>Aktuális feltöltési sebesség</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Kérem, jelölje ki a szinkronizálandó mappát</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>Nincs kapcsolat a szerverrel</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>Minden kapcsolat aktív</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Néhány szerver nem elérhető</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Űrlap</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Embléma</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>Kis méret</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>Bezárás</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Válasszon ki</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>vagy húzzon ide egy könyvtárat a szinkronizáláshoz</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>Letöltési sebesség</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>lefelé nyíl</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>Feltöltési sebesség</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>felfelé nyíl</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Hiba történt a ccnet konfigurálása közben</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Az előre beállított könyvtár "%1" nem hozható létre</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>%1 nem olvasható</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Kötet létrehozása</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Kérem, válasszon könyvtárat</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Létrehozás...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>A kötethez nem sikerült titkosítási kulcsot készíteni</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Kérem, válassza ki a szinkronizálandó könyvtárat</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>A könyvtár (%1) nem létezik</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Kérem, írja be a nevet</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Kérem, adja meg a jelszót</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>A jelszavak nem egyeznek</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ismeretlen hiba</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>A letöltési feladat hozzáadása nem sikerült:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>A kötet nem hozható létre a szerveren:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Útvonal:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Válasszon</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Név:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>Titkosított</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Jelszó:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Jelszó ismételten:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>Állapot</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Rendben</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 kliens inicializálása sikertelen</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Kérem, adja meg a jelszót</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>"%1" kötet szinkronizálása</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>"%1" mappa szinkronizálása</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Szinkronizálás könyvtárba:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>vagy</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>szinkronizálás meglévő könyvtárral</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>új szinkronizáló könyvtár létrehozása</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Szinkronizálás ezzel a létező könyvtárral:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Könyvtár választás</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>A könyvtár nem létezik</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Válassz könyvtárat a szinkronizáláshoz.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>A szervezet megtiltotta hogy a kötetet a(z) %1 könyvtáron kívülre helyezze.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>"%1" fájl konfliktus miatt válassz másik könyvtárat.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>"%1" kötet konfliktus miatt válassz másik könyvtárat.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>"%1" könyvtár már létezik. Biztos, hogy ezzel szinkronizálja (a tartalmak összeadódnak)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Kattintson a Nem-re ha inkább egy új könyvtárral szinkronizálná</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Alternatív könyvtárnév nem található</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>A letöltési feladat létrehozása sikertelen:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>A tároló letöltési információi nem elérhetőek:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Kötet letöltése</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>Tallózás...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>A kötet jelszava:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Rendben</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Módosítások részletei</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Hozzáadott fájlok</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Törölt fájlok</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Megváltozott fájlok</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Hozzáadott könyvtárak</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Törölt könyvtárak</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Megnyitás</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Szülő ma&ppa megnyitása</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Felhő fájlkezelő</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Vissza</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Előre</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Otthon</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Fájlok feltöltése</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Könyvtár feltöltése</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Nincs elegendő jogosultsága, hogy fájlokat töltsön fel a kötetbe</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Könyvtár létrehozása</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Frissítés</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Mappanév</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Érvénytelen könyvtárnév</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>A név "%1" már használatban van.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>újra</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Nem sikerült lekérdezni a fájlinformációkat.<br/>Kérem, %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Ez a könyvtár üres.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>A menteni kívánt fájl neve...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>A "%1" fájl mozgatása sikertelen</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Adja meg az elérési utat ahhoz a könyvtárhoz amibe menteni szeretne...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Felülírja a fájlt: "%1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>"%1" fájl nincs szinkronizálva</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>%1 fájl már létezik.<br/>Felülírja?<br/><small>(Válassza a Nem-et alternatív néven való feltöltéshez).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>%1 fájl letöltése sikertelen</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Fájl kiválasztása feltöltéshez</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Feltöltendő könyvtár kiválasztása</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Átnevezés</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Biztosan törli a kiválasztott elemeket?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>A könyvtár létrehozása nem sikerült</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>A fájl zárolása nem sikerült</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Fájl kiválasztása feltöltéshez: %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Az átnevezés nem sikerült.</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>A törlés nem sikerült.</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>A megosztás nem sikerült.</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>A beillesztési művelet forrása és célja nem lehet azonos</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>A könyvtárat nem lehet beilleszteni a saját alkönyvtárába</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Sikertelen másolás</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Sikertelen áthelyezés</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>A könyvtár létrehozása nem sikerült.</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>Függőben</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Feltölt</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Feltöltés %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Letölt</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Letöltés %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 / %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Művelet megszakítva</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>függőben</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Belső szerverhiba</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>A tárhely megtelt</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>zárolva ennél: %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Név</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Méret</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Utoljára módosítva</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Mentés mint...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>Záro&l</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>Á&tnevezés</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Töröl</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Megosztás csoportnak</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Frissít</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Másolás</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>&Kivágás</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Beillesztés</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>L&etöltés megszakítása</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Szinkronizálja ezt a könyvtárat</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Ez a funkció csak a pro verzióban érhető el.
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>%1 &letöltési hivatkozás készítése</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Megosztás felhasználónak</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>%1 belső hivatkozás k&észítése</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>Menté&s ide mint...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Fe&lold</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Írásvédett fájl törlése sikertelen</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Írásvédett fájl csonkolása sikertelen</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Könyvtárak létrehozása sikertelen</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Átmeneti állományok létrehozása sikertelen</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Fájl diszkre írása sikertelen</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Nem sikerült letörölni a letöltött fájl régi verzióját</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Sikertelen a fájl mozgatása</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 inicializálása</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>%1 könyvtár választása</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Kérem, válasszon egy könyvtárat</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Az inicializálás még nem fejeződött be. Biztosan kilép?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>A mappa (%1) nem létezik</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Embléma</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Könyvtár választása</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Válasszon könyvtárat. A könyvtárban egy %1 alkönyvtárat hozunk létre. Ha egy kötetet letölt alapértelmezetten abba lesz lementve.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Tallózás...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Következő</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 kötetekbe szervezi a fájlokat.
+Letölti az alapértelmezett kötetet?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Alapértelmezett kötet ellenőrzése...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Alapértelmezett kötet létrehozása...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Az alapértelmezett kötet létrehozása nem sikerült:
+
+A funkció használatához a szoftver 2.1-es vagy újabb verzióját kell futtatni a szerveren.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Az alapértelmezett kötet lekérdezése nem sikerült:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Az alapértelmezett kötet létrehozása nem sikerült:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Alapértelmezett kötet letöltése...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Az alapértelmezett kötet letöltése nem sikerült:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Az alapértelmezett kötet letöltése befejeződött.
+A kötet böngészéséhez kattintson a "Megnyitás" gombra.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Hiba történt az alapértelmezett kötet letöltése során: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Az alapértelmezett kötet letöltése nem sikerült:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 kötetekbe szervezi a fájlokat.
+Letölti az alapértelmezett kötetet?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Kihagyás</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Futtatás a háttérben</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Megnyitás</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Befejezés</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Alapértelmezett kötet letöltése</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Igen</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Embléma</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>további betöltése</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Fiók hozzáadása</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Ismételt bejelentkezés</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Bejelentkezés...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Hálózati hiba:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Figyelem:</b> A szerver SSL tanúsítványa nem megbízható. Elfogadja a tanúsítványt?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Kérem, adja meg a szerver címét</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>Érvénytelen elérés: %1</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Kérem, adja meg a felhasználónevet</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Kérem adja meg a számítógép nevét</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 szerver cím</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>A szerver címét ki kell tölteni</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 nem egy valós szerver cím. A címnek 'https://'-sel kell kezdődnie</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Kérem, adja meg a jelszavát</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Érvénytelen e-mail cím vagy jelszó</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Túl sok bejelentkezési kísérlet. Kérem, próbálja meg később.</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Belső szerverhiba</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Sikertelen bejelentkezés: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Sikertelen bejelentkezés</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>Embléma</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Szerver:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Példa: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>vagy: http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Jelszó:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>Állapot</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Számítógép neve:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / felhasználónév:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>pl. Gábor laptopja</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Bejelentkezés</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Kijelentkezett. Kérem</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>jelentkezzen be</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Fiók hozzáadása</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Frissítés</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Megosztás %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Kérem írja be a csoport nevét</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Kérem adja meg a felhasználói nevet vagy e-mail címet</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>A feltöltés sikeres</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>A megosztás meghiúsult: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>A törlés sikeres</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Nem sikerült lekérdezni a könyvtár megosztási információit</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Nem sikerült lekérdezni a csoport és kapcsolat információkat</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Kérem, adja meg a felhasználónevet</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Kérem írja be a csoport nevét</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>"%1" csoport nem létezik</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Már létezik %1 csoporthoz megosztás</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Már létezik %1 felhasználóhoz megosztás</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Az előző folyamat még nem fejeződött be</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Megosztás ide:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Megosztás</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Jogosultság:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Írható-olvasható</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Csak olvasható</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Bezárás</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>Szinkronizálva</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>Fájlok indexelése</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Szinkronizálás inicializálása</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>Letöltés</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>Feltöltés</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>Egyesítés</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>Várakozás a szinkronizálásra</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>Nincs kapcsolat a szerverrel</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>Azonosítás</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>Automatikus szinkronizálás kikapcsolva</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>Ismeretlen</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ismeretlen hiba</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Hálózati hiba</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>A proxy nem található</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>A szerver nem található</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>A szerverhez nem lehet kapcsolódni</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Nem létesíthető biztonságos kapcsolat. Ellenőrizze a szerver SSL tanúsítványát</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>Az adatátvitel megszakadt. Ellenőrizze a hálózatot vagy tűzfalat</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Adatátviteli időtúllépés. Ellenőrizze a hálózatot vagy tűzfalat</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Nem kezelt http átirányítás a szervertől. Ellenőrizze a szerver beállítását</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Szerverhiba</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Nincs elég memória</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>A kliensre nem lehet adatot írni. Ellenőrizze a tárhelyet vagy a könyvtár jogokat</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>A tárhely kvóta megtelt</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>A kötet törölve a szerveren</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>A kötet megsérült a szerveren</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>A tárhely megtelt</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Inicializálás...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>Kapcsolódás a szerverhez...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>Fájlok indexelése...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Letöltési fájl lista...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Fájlok letöltés alatt...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Könyvtár létrehozása...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Változások egyesítése...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Kész</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>szerver információ ellenőrzése...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Megszakítás</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Megszakítva</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL hiba</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Hálózati hiba: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Szerverhiba</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>A tanúsítvány-adatbázis nem nyitható meg</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>"%1" fájl nem létezik itt: "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 nem található olyan alkalmazás amivel a(z) %2 fájl megnyitható</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Elkészített kötet "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Törölt kötet "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>%1 átnevezése</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Nem lehet letölteni: "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>Sikertelen másolás</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Hozzáadva</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Törölve</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Törölve</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Módosítva</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Átnevezve</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Új vagy módosított</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Átmozgatva</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Könyvtár hozzáadva</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Könyvtár törölve</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Könyvtár átnevezve</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Könyvtár átmozgatva</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>fájlok</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>könyvtárak</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>és további %1 </translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>A könyvtár visszaállítva erre a státuszra:</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>"%1" fájl visszaállítva erre a státuszra: %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Törölt könyvtár visszaállítva</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Könyvtár neve vagy leírása változott</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>%1 rendszer automatikusan összefűzte</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Épp az imént</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>tegnap</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 napja</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 órája</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 órája</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 perce</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 perce</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Nem része a tanúsítványnak></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Szinkronizálja ezt a kötetet ide:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Szinkronizálja ezt a könyvtárat ide:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Mappa</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Írásvédett mappa</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Dokumentum</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF dokumentum</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Kép fájl</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Szöveges dokumentum</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Hang fájl</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Videó fájl</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word dokumentum</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint dokumentum</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel dokumentum</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Az útvonal ("%1") ütközik a rendszer elérési útvonalával</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Az útvonal ("%1") ütközik egy meglévő kötet elérési útvonalával</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>fájl lista feltöltése</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>A fájlt más alkalmazás fogja</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>A könyvtárat más alkalmazás fogja</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>A fájlt más felhasználó használja</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Érvénytelen útvonal</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Hiba az indexeléskor</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>Az útvonal szóközzel vagy ponttal végződik</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>Az útvonal érvénytelen karaktert tartalmaz mint '|' vagy ':'</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>"%1" kötet</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Ez a kötet még nincs letöltve</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Hiba:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>%1 másodpercenként</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Tároló ikonja</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Tároló neve</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Szövegcímke</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Tulajdonos:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Utoljára módosítva:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Méret:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Helyi elérési útvonal:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Állapot:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Tároló állapota</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Név:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Szinkronizálási időköz:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Bezárás</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Ez a kötet nincs letöltve</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>"%1" fájlt nem lehet megnyitni a nemlétező kötetből: "%2"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Mostanában frissült könyvtárak</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Saját kötetek</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Alkötetek</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Velem megosztva</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Mindenkivel megosztva</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Csoportokkal megosztva</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Szinkronizált könyvtárak</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Szinkronizálás inicializálása</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Automatikus szinkronizálás kikapcsolása</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Automatikus szinkronizálás bekapcsolása</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>&Tulajdonságok megjelenítése</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Kötet tulajdonságai</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Szinkronizálja ezt a kötetet</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Szinkronizálja ezt a kötetet</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Mostanában frissült könyvtárak</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Szinkronizálás &most</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Kötet azonnali szinkronizálása</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Letöltés megszakítása</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>A kötet letöltésének megszakítása</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Mappa megnyitása</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>Helyi mappa megnyitása</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>&Helyi mappa megnyitása</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Szinkronizálás befejezése</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Kötet szinkronizálásának megszüntetése</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>Megnyitás a &felhőben</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>Kötet böngészése a seahub-on</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Megosztás felhasználónak</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Kötet megosztása a felhasználónak</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Megosztás csoportnak</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Kötet megosztása csoporttal</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>Fe&lhő fájlkezelő megnyitása</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>kötet megnyitása beágyazott fájlkezelőben</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Kötet újraszinkronizálása</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>kötet szinkronizálásának megszüntetése és újraszinkronizálása</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Sz&inkronizálási időköz beállítása</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>A kötet ("%1") szinkronizálását nem sikerült megszüntetni</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>A művelet megszakítása sikertelen:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Letöltés megszakítva</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Nincs joga feltölteni ebbe a könyvtárba</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>"%1" fájl nem írható felül saját magával</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>A "%1" fájl törlése nem sikerült.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Sikertelen feltöltés: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Szinkronizálási időköz (másodpercben):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>"%1" kötet szinkronizálási időközének beállítása</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Kötetek keresése</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>újra</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Nem sikerült lekérdezni a kötet információkat.<br/>Kérem, %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Figyelem:</b> A szerver biztonsági tanúsítványa nem megbízható. Folytatja a kapcsolódást?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>A naplózás elindítása nem sikerült: %S</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Rendben</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Igen</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nem</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 belső link</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Vágólapra másol</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Rendben</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ismeretlen hiba</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Automatikus szinkronizálás kikapcsolása</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Automatikus szinkronizálás bekapcsolása</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Kilépés</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Főablak megnyitása</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Beállítások</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>%1 könyvtár &megnyitása</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>%1 mappa megnyitása</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Nap&lózási mappa megnyitása</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Fájl szinkronizációs hibák megmutatása</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Névjegy</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Megjeleníti az alkalmazás névjegyét</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Online segítség</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Fájl</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>Automatikus szinkronizálás kikapcsolva</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Feltöltés</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Letöltés</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>%1 naplóállományok könyvtárának megnyitása</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>%1 online súgó megnyitása</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Néhány szerver nem elérhető</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Könyvtárban mutat</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Könyvtárban mutat</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Fájlok keresése</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>újra</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Keresés sikertelen<br/>Kérem, %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Kapcsolódás állapota</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>Kapcsolódva</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>Nincs kapcsolat</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Bezárás</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Kérem adja meg a kötet jelszavát</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Jelszó megadása ehhez a kötethez: %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Adja meg a jelszót</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Érvénytelen jelszó</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ismeretlen hiba</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Rendben</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Beállítások</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>%1 automatikus elindítása bejelentkezéskor</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Ne jelenjen meg %1 ikonja a tálcán</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Nincs</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP proxy</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 proxy</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Rendszer Proxy</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Megváltoztatta a felület nyelvét. Újraindítja az alkalmazást a beállítás érvényesítéséhez?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>A proxy kiszolgáló címe nem lehet üres</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Helytelen Proxy portszám</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>A proxy felhasználói név nem lehet üres</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>A proxy jelszó nem lehet üres</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Főablak elrejtése indításkor</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Értesítést kérek, ha a kötetek szinkronizálva vannak</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>MS Office/Libreoffice ideiglenes fájlok szinkronizálása</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Letöltési sebesség korlátozása (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Feltöltési sebesség korlátozása (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Alap</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>A szinkronizálás maradjon bekapcsolva</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>A szinkronizálás maradjon bekapcsolva a helyi mappa törlése vagy elérhetetlensége esetén</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Ne legyen megszüntetve a szinkronizálás, ha a kötet nem létezik a szerveren</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Ne legyen automatikusan megszüntetve a szinkronizálás, ha a kötet nem létezik a szerveren</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>„FinderSync” kiterjesztés engedélyezése</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>„Explorer” kiterjesztés engedélyezése</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Frissítések automatikus keresése</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Tanúsítványellenőrzés kikapcsolása HTTPS-alapú szinkronizálásnál</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Szinkronizálás engedélyezése létező könyvtárral más névvel</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Haladó</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Nyelv (újraindítást igényel)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Nyelv</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Proxy típusa:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Szerver:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Felhasználónév:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Jelszó:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>A proxy szerver jelszót igényel</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Hálózat</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Rendben</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Mégsem</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Írható olvasható</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Csak olvasható</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Megosztás megszüntetése</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Kattintson a szerkesztéshez</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>%1 készítette</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Írható olvasható</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Csak olvasható</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Csoport</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Felhasználó</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Jogosultság</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Az előző folyamat még nem fejeződött be</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Megosztás link</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Megosztása link:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Közvetlen letöltés</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Vágólapra másol</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Rendben</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Nem megbízható kapcsolat</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>A szerver (%1) érvénytelen biztonsági tanúsítványt használ, ezért a kapcsolat nem megbízható. Folytatja a kapcsolódást?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Jelenlegi RSA-kulcs ujjlenyomata: %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Előző RSA-kulcs ujjlenyomata: %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Választás megjegyzése</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Igen</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nem</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Megnyitás</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Fájl megnyitása</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>megtekintés &Weben</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>fájl megtekintése a weboldalon</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>újra</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Nem sikerült lekérdezni a kedvenc fájlok információit<br/>Kérem, %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Nincsenek kedvenc fájljai.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Fájl szinkron hibák</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Nincsenek szinkronizációs hibák. </translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Kötet megnyitása dupla kattintással</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Kötet</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Útvonal</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Hiba</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Idő</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>%1 eltávolítása</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Biztosan eltávolítja a következő fiók beállításait: %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Fiókinformációk eltávolítása...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Párbeszédablak</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>szöveg</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Igen</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nem</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="is" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>mistókst að opna gagnagrunn reiknings</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Aðgangur útrunninn, vinsamlegast skráðu þig inn aftur</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Persónulegar stillingar</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Vinsamlegast setjið inn veffang þjóns</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 er ekki rétt veffang þjóns</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Mistókst að vista reikningsupplýsingar</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Mistókst að vista breytingarnar: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Tókst með ágætum að uppfæra reikningsupplýsingar</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Svargluggi</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Veffang Þjóns</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Netfang</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í lagi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Mistókst að taka samstilla af fyrir þennan reikning: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>smelltu til að opna vefsíðuna</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>Sér útgáfa</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Enginn reikningur</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Veldu</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Stillingar reiknings</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Innskrá</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Eyða</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Bæta við reikningi</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Útskrá</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>ekki skráður inn</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Reikningur</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>netfang</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>þjónn</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Virkni er aðeins studd í %1 Server Professional Edition.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reyna aftur</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Mistókst að sækja upplýsingar um hreyfingar. Vinsamlegast %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Upphleðsla Tókst</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Skrá "%1"
+hlaðið upp giftursamlega.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Skrá "%1"
+mistókst að hlaða upp.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Mistókst að búa til skráarsafn fyrir smámyndir</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Niðurhalsverk</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>fjarlægja öll verk sem eru kláruð</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Engin niðurhalsverk akkúrat núna.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Svargluggi</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Hreinsa</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Loka</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Safn</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Slóð</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Hætta við þetta verk</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>hætta þessu verki</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Fjarlægja þetta verk</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Mistókst að hætta við þetta verk:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Mistókst að fjarlægja þetta verk:
+
+ %1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minnka</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Loka</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Söfn</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Stjörnumerkt</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Hreyfingar</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Leita</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>núverandi niðurhalshraði</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>núverandi upphleðsluhraði</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Vinsamlegast veldu skáarsafn til að samkeyra</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>enginn þjónn tengdur</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>allir þjónar tengdir</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>sumir þjónar ekki tengdir</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minnka</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>loka</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Veldu</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>eða Dragðu og Slepptu skráarsafni hingað</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>niðurhalshraði</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>ör niður</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>upphleðsluhraði</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>ör upp</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Villa þegar verið var að búa til styllingar fyrir ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Get ekki búið til frumstillt möppu "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>tókst ekki að lesa %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Búa til safn</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Vinsamlegast veldu skráarsafn</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Er að búa til...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Mistókst að útbúa dulkóðunarlykil fyrir þetta safn</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Vinsamlegast veldu skráarsafn til að samstilla</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Skráarsafnið %1 er ekki til</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Vinsamlegast sláðu inn nafn</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vinsamlegast sláðu inn lykilorðið</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Lykilorðin stemma ekki</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Óþekkt villa</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Tókst ekki að bæta við niðurhalsverki:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Mistókst að búa til safn á þjóni:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Svargluggi</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Slóð:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Veldu</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nafn:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>dulkóðað</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Lykilorð:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Endurtaktu Lykilorðið:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>stöðutexti</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í lagi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 biðlara mistókst að frumstilla</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vinsamlegast sláðu inn lykilorðið</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Samstilla safn "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Samstilla möppu "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Samkeyra við möppu:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>eða</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>samkeira með möppu ser er nú þegar til</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>búa til nýja samkeyrslumöppu</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Samkeyra með þessari möppu:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Vinsamlegast veldu möppu</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Þessi mappa er ekki til</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Vinsamlegast veldu möppu til að samkeyra</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Samfélagið sem þú tilheyrir hefur afvirkjað möguleikann að setja safn útfyrir %1 möppuna.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Rekst á við skránna "%1" sem er nú þegar til, vinsamlegast veldu aðra möppu.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Rekst á við möppuna "%1" sem er nú þegar til, vinsamlegast veldu aðra</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Mappan "%1" er þegar til. Ertu viss um að þú viljir samkeyra við hana (efni hennar verður skeytt inn)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Veldu Nei til að samkeyra frekar við nýja möppu</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Get ekki fundið annað möppunafn</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Mistókst að bæta við niðurhalsverki:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Mistókst að sækja niðurhalsgeymsluupplýsingar :
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Hala niður safni</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>veldu...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Lykilorð fyrir þetta safn:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í lagi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Breytingar í smáatriðum</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Bætti við skrám</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Eyddar skrár</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Breyttar skrár</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Nýjar möppur</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Eyddar möppur</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Opna</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Opna &yfir skáasafn</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Skýjavafri</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Til baka</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Áfram</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Heim</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Hlaða upp skrám</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Hlaða upp möppu</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Þú hefur ekki réttindi til að upphlaða skrám í þetta safn</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Búa til möppu</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Endurglæða</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Möppunafn</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Óleyfilegt möppunafn!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Þetta nafn "%1" er þegar í notkun.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reyna aftur</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Mistókst að sækja upplýsingar skáa<br/>Vinsamlegast %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Sláðu inn nafn á skrá til að vista í...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Gat ekki fjarlægt skránna "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Sláðu inn slóð möppunnar sem þú vilt vista í...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Vilti örugglega yfirskrifa núverandi skrá "%1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Skrá "%1" hefur ekki verið samstillt</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Skrá %1 er þegar til.<br/>Viltu yfirskrifa hana?</br/></small>(Veldu Nei til að hlaða upp með öðru nafni).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Mistókst að niðurhala skrá: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Veldu skrá til að hlaða upp</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Veldu möppu til að hlaða upp</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Endurnefna</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Viltu virkilega eyða þessum atriðum</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Mistókst að búa til möppu</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Læsing skráar mistókst</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Veldu skrá til að uppfæra %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Endurnefning mistókst</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Eyðing mistókst</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Deiling mistókst</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Get ekki sleppt skránum í sama skráasafn</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Afritun mistókst</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Færsla mistókst</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Mistókst að búa til safn!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Upphlaða</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Hleð upp %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Niðurhala</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Hala niður %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 af %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Hætt við aðgerð</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>yfirstandandi</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Innri Kerfisvilla</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>læst af %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nafn</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Stærð</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Síðast Breytt</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Vista sem...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Læsa</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Endurnefna</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Eyða</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Deila með Hópi</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Uppfæra</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Copy</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Cu&t</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Paste</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Hætt&a við niðurhal</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Samkeyra þessu skráasafni</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Þessi virkni er aðeins aðgengileg í "pro" útgáfunni
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Gera %1 Niðurhalshlekk</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Deila með Notanda</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>G&era %1 Innri Hlekk</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Vista sem í...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Af&læsa</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Get ekki fjarlægt skrifvarnar skrár</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Get ekki klippt skrifvarðar skrár</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Mistókst að búa til skráarsöfn</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Mistókst að búa til tímabundna skrá</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Mistókst að skrifa skrá á disk</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Mistókst að eyða eldri útgáfu af niðurhöluðu skránni</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Mistókst að færa skrá</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Frumstillt</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Veldu %1 möppu</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Vinsamlegast veldu skráarsafn</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Frumstillingu er ekki lokið. Virkilega hætta núna?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Skráarsafnið %1 er ekki til</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Svargluggi</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Veldu möppu</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Vinsamlegast veldu möppu. Við munum búa til %1 undirmöppu í henni. Þegar þú halar niður safni, þá er það sjálfgefið að vista þar.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Veldu...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Næsta</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Athuga sjálfgefna skráarsafnið þitt...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Bý til sjálfgefna safnið...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Mistókst að eyða sjálfgefnu safni:
+
+Þjónsútgáfan verður að vera 2.1 eða hærri til að styðja þetta</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Mistókst að sækja sjálfgefið safn:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Mistókst að búa til sjálfgefið safn:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Hala niður sjálfgefna safninu...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Mistókst að hala niður sjálfgefnu safni:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Sjálfgefna safninu hefur verið halað niður.
+Þú getur smellt á "Opna" takkann til að skoða það.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Villa þegar verið var að hala niður sjálfgefna safninu: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Mistókst að hala niður sjálfgefnu safni:
+ %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Samræður</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Sleppa</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Keyra í Bakgrunni</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Opna</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Enda</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Hala niður Sjálfgefnu Safni</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Já</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Bæta við reikningi</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Endur-innskráning</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Er að innskrá...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Netvilla:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Viðvörun:</b> ssl skilríkið fyrir þennan þjón er ótreyst, halda samt áfram?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Vinsamlegst sláðu inn veffang þjóns</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 er ekki gilt vefang þjóns</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Vinsamlegst sláðu inn notendanafn</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Vinsamlegast skráðu heiti tölvunnar</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 Veffang Þjóns</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vinsamlegast sláðu inn lykilorð</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Ekki rétt netfang eða lykilorð</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Ert að skrá þig inn of ört, vinsamlegast bíddu aðeins</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Innri Kerfisvilla</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Innskráning mistókst: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Innskráning mistókst</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Svargluggi</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Þjónn:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Til dæmis: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>eða http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Lykilorð:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>stöðutexti</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Tölvunafn:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Netfang / Notendanafn:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>t.d Siggu tölva</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Innskrá</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Þú er útskráð(ur). Vinsamlegast</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>innskrá</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Bæta við reikningi</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Endurglæða</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Deila %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Sláðu inn nafn hópsins</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Tókst að hlaða upp</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>Deiliaðgerð mistókst: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Tókst að fjarlægja</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Mistókst að sækja upplýsingar um möppuna</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Mistókst að sækja hópa og tengiliðstupplýsingarnar þínar</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Vinsamlegast sláðu inn notendanafnið</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Vinsamlegast sláðu inn hópanafnið</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Enginn slíkur hópur "%1"</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Þegar deilt með hópi %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Þegar deilt með notanda %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Síðasta aðgerð er enn í vinnslu</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Samræður</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Deila Með:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Deila</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Réttindi:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lesa-Skrifa</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Aðeins-Lesa</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Loka</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>samstillt</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>Bý til yfirlit yfir skrár</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>frumstilli samstillingu</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>hala niður</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>hleð upp</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>sameina samstillingar</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>bíð eftir samstilingu</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>þjónn ekki tengdur</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>auðkenning þjóns</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>slökkt er á sjálfvirkri samstillingu</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>óþekkt</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Óþekkt villa</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Geymslukvóti hefur verið fullnýttur</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Frumstilli...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>tengist þjóni...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>Bý til yfirlit yfir skár...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Hala niður skráalista...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Hala niður skrám...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Bý til skráarsafn...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Sameina skráarbreytingar...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Búin</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Hætta við</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Hætt við</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL Villa</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Netvilla: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Kerfisvilla</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>mistókst að opna vottorðagagnagrunn</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Skrá "%1" er ekki til í "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 gat ekki fundið forrit til að opna skránna %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Bjó til safnið "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Eyddi safninu "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Endurnefna %1 sem</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Gat ekki niðurhalað atriði "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>afritun mistókst</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Bætt við</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Eytt</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Fjarlægt</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Breytt</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Endurnefnt</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Bætt við eða breytt</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Fært</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Bætti við skráarsafni</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Fjarlægði skráarsafn</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Endurnefndi skráarsafn</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Færði skráarsafn</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>skrár</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>skráarsöfn</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>og %1 fleiri</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Setti stöðu safns á</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Snéri skrá "%1" aftur í stöðu "%2" </translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Endurheimti eyddu skráarsafni</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Breytti nafni eða lýsingu skráarsafns</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Sameinað sjálfvirkt af %1 kerfi</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Rétt í þessu</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>Fyrir einum degi síðan</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>Fyrir %1 dögum síðan</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>Fyrir einni klukkustund síðan</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>Fyrir %1 klukkustundum síðan</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>Fyrir einni mínútu síðan</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>Fyrir %1 mínútum síðan</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Samkeyra þessu safni með:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Samkeyra þessu skráasafni með:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Skráasafn</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Skrifvarið Skráasafn</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Skjal</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF Skjal</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Myndaskrá</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Textaskjal</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Hljóðskrá</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Vídeóskrá</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word skjal</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint skjal</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel skjal</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Slóðin "%1" rekst á við kerfisslóð</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Slóðin "%1" rekst á við safn sem þegar er til</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Safn "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Ekki er enn búið að hala niður þessu safni</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Villa:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>hverjar %1 sekúndur</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Svargluggi</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>SafnaSmámynd</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>SafnaNafn</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>TextaMerki</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Eigandi:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Síðast Breytt:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Stærð:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Staðvær Slóð:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Staða:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>SafnaStaða</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nafn:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Samstillingartíðni:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Loka</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Þessu safni hefur ekki enn verið halað niður</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Get ekki opnað skrá "%1" því safnið "%2" er ekki til</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Nýlega Uppfært</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Söfnin mín</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Undirsöfn</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Samstillt Söfn</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>frumstilli samstillingu</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Afvirkja sjálfvirka samstillingu</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Virkja sjálfvirka samstillingu</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Sýna &smáatriði</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Sýna smáatriði varðandi þetta safn</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Samstilla þetta safn</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Samstilla þetta safn</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Nýlega Uppfært</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Samkeyra &núna</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Samkeyra þetta safn núna</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Hætta við niðurhal</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Hætta við niðurhal á þessu safni</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Opna skráarsafn</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>opna staðvært skráarsafn</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Samstilling Af</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>aftengja þetta safn</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Skoða í skýi</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>skoða þetta safn á seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Deila með notanda</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Deila þessu safni með notanda</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Deila með hópi</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Deila þessu safni með hópi</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Opna skráavafra skýs</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>opna þetta safn í innbyggðum Skráavafra Skýs </translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Endursamstilla þetta safn</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>Taka af og setja aftur á samstillingu fyrir þetta safn</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Setja &samstillingartíðni</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Mistókst að aftengja safnið "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Mistókst að hætta við þetta verk:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Hætt var við niðurhalið</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Gat ekki yfirskrifað skrána "%1" með sjálfri sér</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Gat ekki eytt skránni "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Mistókst að hlaða upp skránni: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Samstillinartíðni (í sekúndum):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Setja Samstillingartíðni Fyrir Safn "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reyna aftur</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Tókst ekki að sækja upplýsingar um safn<br/>Vinsamlegast %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Viðvörun:</b> ssl skírteinið fyrir þennan þjón er ekki traust, halda samt áfram?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Mistókst að frumstilla skrá: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í lagi</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Já</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nei</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 Innri Hlekkur</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Afrita í skyndimynni</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í Lagi</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Óþekkt villa</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Skökkva á sjálfvirkri samstillingu</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Kveikja á sjálfvirkri samstillingu</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Hætta</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Sýna aðalglugga</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Stillingar</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Opna %1 &skráasafn</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>opna %1 skáasafn</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Opna skráarsafn &skráninga</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Um</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Sýna upplýsingar um forritið</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Hjálp á netinu</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Skrá</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>slökkt er á sjálfvirkri samstillingu</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Hleð upp</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Hala niður</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>opna %1 sögu skráasafns</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>opna %1 hjálp á netinu</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>sumir þjónar ekki tengdir</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Sýna í skráasafni</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Sýna í skráasafni</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>reyna aftur</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Leit mistókst<br/>Vinsamlega %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Tengistaða þjóns</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>tengt</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>aftengt</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Samræða</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Loka</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Vinsamlegast sláðu inn lykilorð safnsins</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Sláðu inn lykilorð fyrir safnið %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vinsamlegast sláðu inn lykilorð</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Rangt lykilorð</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Óþekkt villa</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Samræður</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í lagi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Stillingar</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Keyra %1 upp sjálfvirkt eftir innskráningu</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Fela %1 smámynd frá stjórnstiku</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Ekkert</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP Proxy</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 Proxy</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Proxy Kerfi</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Þú hefur skipt um tungumál. Endurræsa til að virkja það?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>Proxy veffang má ekki vanta</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Proxy tengið er rangt</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>Proxy notandanafn má ekki vanta</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>Proxy lykilorð má ekki vanta</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Samræður</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Fela aðalglugga í ræsingu</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Láta vita þegar söfn eru samstillt</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Virkja samstillingu tímabundinna skráa af gerð MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Takmörkun á hraða niðurhals (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Takmörkun á hraða uppleðslu (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Einfallt</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Ekki taka samstillingu sjálfvirkt af safni</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Ekki taka samkeyrslu af safni þegar skráarsafn á tölvu er fjarlægt eða ekki aðgengilegt af einhverjum völdum.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Ekki taka samstillingu af safni þegar það finnst ekki á þjóni</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Ekki taka samstillingu af safni sjálfvirkt þegar það finnst ekki á þjóni</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Virkja FinderSync viðbót</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Virkja Explorer viðbót</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Ekki sannvotta skírteini í HTTPS samstillingu</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Virkja samkeyrslu við skráasafn sem er nú þegar til undir öðru nafni</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Ýtarlegt</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Tungumál (þarfnast endurræsingar)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Tungumál</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Staðgengilsgerð:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Hýsill:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Tenginúmer:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Notendanafn:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Lykilorð:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Staðgengilsþjónn krefst lykilorðs</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Net</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í lagi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Hætta við</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lesa Skrifa</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Aðeins Lesa</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Fjarlægja Deilingu</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Búið til af %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lesa Skrifa</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Aðeins Lesa</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Hópur</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Notandi</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Réttindi</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Síðasta aðgerð er enn í vinnslu</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Deila Hlekk</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Deila hlekk:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Beint Niðurhal</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Afrita í biðminni</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Í Lagi</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Ótraust tenging</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 notar rangt öryggisskíreini. Tengingin er hugsanlega óörugg. Viltu halda áfram?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Núverandi RSA fingrafar er %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Fyrra RSA fingrafar var %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Samræða</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Mundu valið mitt</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Já</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nei</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>%Opna</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Opnaðu þessa skrá</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>skoða á &Vef</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>skoða þessa skrá á vefsíðu</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>reyna aftur</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Mistókst að sækja upplýsingar um stjörnumerktar skrár<br/>Vinsamlegast %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Þá hefur ekki stjörnumerkt skrár enn</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Fjarlægja %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Viltu fjarlægja reikningsupplýsingar %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Fjarlægi reikningsupplýsingar...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Svargluggi</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>texti</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Já</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nei</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="it" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Informazioni su %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Client %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5>REV %1</h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Informazioni</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Controlla aggiornamenti</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>Impossibile aprire il database degli account</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Autorizzazione scaduta, per favore effettua il login</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Impostazioni account</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Inserisci l'indirizzo del server</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 non è un indirizzo valido per il server</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Impossibile salvare le informazioni dell'account</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Impossibile salvare i cambiamenti: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Informazioni dell'attuale account correttamente aggiornate</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Indirizzo Server</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>Sei sicuro di voler rimuovere l'account %1?<br><br>L'account sarà rimosso localmente. Anche tutte le configurazioni di sincronizzazione saranno rimosse. L'account sul server non sarà toccato.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Impossibile scollegare le librerie dell'account: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>Clicca per aprire il sito web</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>Versione Pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Nessun account</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Scegli</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Impostazioni account</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Login</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Cancella</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Aggiungi un account</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Disconnetti</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>non autenticato</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Modulo</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Account</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>server</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Le Attività File sono supportate soltanto in %1 Server Professional Edition.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>riprova</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Impossibile ottenere informazioni sulle attività.<br\>Per favore %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Caricamento riuscito</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>File "%1"
+caricato con successo.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>File "%1"
+non caricato a causa di un errore.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Errore di permessi!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorizzazione scaduta</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Il file non esiste</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Errore di caricamento: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Impossibile creare cartella degli avatar</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Controllo i permessi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Attività di scaricamento</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>rimuovi tutte le attività completate con successo</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Nessun processo di scaricamento attivo.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Svuota</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Chiudi</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Libreria</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Percorso</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Annulla questa attività</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>annulla questa attività</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Rimuovi questa attività</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Impossibile annullare questa attività:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Impossibile rimuovere questa attività:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimizza</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Chiudi</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Librerie</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Preferiti</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Attività</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Ricerca</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>velocità di scaricamento attuale</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>velocità di caricamento attuale</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Per favore Scegli una cartella da sincronizzare</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>nessun server connesso</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>tutti i server sono connessi</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>alcuni server non sono connessi</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Modulo</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimizza</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>chiudi</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Seleziona</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>marchio</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>o trascina qui la cartella per sincronizzarla</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>velocità di scaricamento</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>Freccia Giù</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>velocità di caricamento</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>Freccia Su</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Errore nel creare la configurazione ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Impossibile creare la directory di preconfigurazione "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>impossibile leggere %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Crea una libreria</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Scegli una cartella</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Creazione...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Impossibile generare la chiave di cifratura per questa libreria</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Scegli la cartella da sincronizzare</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La cartella %1 non esiste</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Inserisci il nome</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Inserisci la password</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Le password non corrispondono</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Errore sconosciuto</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Impossibile aggiungere l'attività di download
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Impossibile creare la libreria sul server:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Percorso:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Scegli</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nome:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>cifrato</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Password:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Ripeti la Password:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>testo di stato</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>Impossibile inizializzare il client %1</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Inserire la password</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sincronizza la libreria "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Sincronizza la cartella "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Sincronizza con la cartella:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>oppure</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>sincronizza con una cartella esistente</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>crea una nuova cartella di sincronizzazione</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Sincronizza con questa cartella esistente:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Scegli una cartella</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>La cartella non esiste</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Scegli la cartella da sincronizzare.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>La tua organizzazione vieta di collocare una libreria al di fuori della cartella %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>In conflitto con il file esistente "%1", scegli un'altra cartella.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>In conflitto con la libreria esistente "%1", scegli un'altra cartella.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>La cartella "%1" esiste già. Vuoi davvero sincronizzare con essa (i contenuti saranno riuniti)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Seleziona No per sincronizzare invece con una nuova cartella</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Impossibile trovare un nome alternativo per la cartella</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Impossibile aggiungere l'attività di scaricamento:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Impossibile ottenere informazioni sullo scaricamento della libreria:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Scarica libreria</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>scegli...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Password per questa libreria:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Dettagli delle modifiche</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>File aggiunti</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>File cancellati</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>File modificati</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Cartelle aggiunte</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Cartelle cancellate</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Apri</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Apri directory &superiore</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Visualizzatore dei file remoti</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Indietro</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Avanti</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Home</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Carica file</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Carica una cartella</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Non hai il permesso di caricare file in questa libreria</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Crea una cartella</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Aggiorna</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 oggetti</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Nome della cartella</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Nome della cartella non valido!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Il nome "%1" è già in uso.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>riprova</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Impossibile caricare le informazioni sui file<br/>Per favore %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Questa cartella è vuota.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Inserisci il nome del file per il salvataggio...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Impossibile cancellare il file "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Inserisci il percorso della cartella per il salvataggio...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Vuoi sovrascrivere il file esistente "%1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Il file "%1" non è stato sincronizzato</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Il file %1 esiste già.<br/>Vuoi sovrascriverlo?<br/><small>(Scegli No per caricarlo usando un altro nome.)</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Il file non esiste</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Impossibile scaricare il file: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Scegli un file da caricare</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Scegli una cartella da caricare</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Rinomina</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Vuoi davvero cancellare questi oggetti</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Impossibile creare la cartella</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Impossibile bloccare il file</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Scegli un file da caricare %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Impossibile rinominare</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Impossibile cancellare</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Impossibile condividere</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Non puoi incollare file dalla stessa cartella</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>Non puoi incollare la cartella in una sua sottocartella</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Impossibile copiare</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Impossibile spostare</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Impossibile creare la libreria</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Non hai i permessi per caricare in questa cartella</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorizzazione scaduta</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Errore di Permessi!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Libreria/Cartella non trovata.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Impossibile caricare il file %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>Impossibile creare la cartella della cache</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>Impossibile aprire la cartella della cache</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Cerca file</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>In corso</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Carica</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Sto caricando %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Scarica</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Sto scaricando %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 di %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Impossibile caricare il file: "%1", vuoi riprovare?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Riprova</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Salta</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Annulla</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Sto salvando</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Salvataggio del file fallito</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Nome</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Dimensione</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Ultima Modifica</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Mostra nella cartella</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostra nella cartella</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operazione annullata</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>in corso</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>attività annullata</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Errore interno del server</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>La quota di spazio disponibile è stata esaurita</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>bloccato da %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nome</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Dimensione</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Ultima modifica</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Salva con nome...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Blocca</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Rinomina</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>Ca&ncella</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Condividi con il gruppo</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Aggiorna</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Copia</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>&Taglia</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Incolla</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>&Annulla scaricamento</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Sincronizza questa cartella</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Questa funzionalità è disponibile solo nella versione pro
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Genera il link %1 per scaricare</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Condividi con l'utente</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>G&enera il link %1 interno</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Salva col nome in...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Sb&locca</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Impossibile cancellare file in sola lettura</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Impossibile tagliare file in sola lettura</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Ritenta il caricamento</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Cancella la versione locale </translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Salva la versione locale come...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Apri la cartella locale della Cache</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Impossibile creare le cartelle</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Impossibile creare file temporanei</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Impossibile scrivere file su disco</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Impossibile rimuovere la versione più vecchia del file scaricato</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Impossibile spostare il file</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Inizializzazione</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Scegli la cartella %1</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Scegli una cartella</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inizializzazione non completata. Vuoi davvero terminare?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>La cartella %1 non esiste</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Scegli una cartella</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Per favore, scegli una cartella. Al suo interno sarà creata la sottocartella %1. Quando scaricherai una libreria, sarà salvata in quella posizione per default.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Scegli...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Prossimo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancella</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organizza i file in librerie.
+Vuoi scaricare la tua libreria predefinita?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Sto verificando la tua libreria predefinita...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Sto creando la libreria predefinita...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Impossibile creare la libreria predefinita:
+
+La versione del server deve essere 2.1 o più alta per supportare questa funzione.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Impossibile accedere alla libreria predefinita:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Impossibile creare la libreria predefinita:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Sto scaricando la libreria predefinita...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Impossibile scaricare la libreria predefinita:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>La libreria predefinita è stata scaricata.
+Premi il pulsante "Apri" per visualizzarla.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Errore durante lo scaricamento della libreria predefinita: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Impossibile scaricare la libreria predefinita:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organizza i file in librerie.
+Vuoi scaricare la tua libreria predefinita?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Salta</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Esegui in background</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Apri</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Finisci</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Scarica libreria predefinita</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sì</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>carica altro</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Caricamento dei file di log falliti</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Caricamento dei file di log</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Errore di permessi!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Libreria/Cartella non trovata.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorizzazione scaduta</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Fallito il caricamento del file di log: %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Caricamento dei file di log riuscito </translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>In compressione</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 di%2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Aggiungi un account</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Accesso singolo</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Nuovo login</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Sto entrando...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Errore di Rete:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Attenzione:</b> Il certificato ssl di questo server non è verificato, procedere comunque?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>inserisci l'indirizzo del server</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 non è un nome valido per il server</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Inserisci il nome utente</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Per favore inserisci il nome del computer</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 Indirizzo del Server</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>L'indirizzo del server non può essere vuoto</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 non è un indirizzo valido. Deve iniziare con "https://"</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Inserisci la password</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Email o password sbagliati</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Ti stai autenticando con troppa frequenza, per favore attendi un minuto</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Errore Interno del Server</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Impossibile effettuare il login: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Accesso fallito</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Server:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Per esempio: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>o http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Password:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>stato testo</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Nome del Computer:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Nome Utente:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>e.g. PC di Mario Rossi</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Accesso</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancella</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Login Automatico</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Sei Uscito. Per favore</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>accedi</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Aggiungi un account</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Aggiorna</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Condividi %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Inserisci il nome del gruppo</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Inserisci nome utente e password</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Aggiornato con successo </translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Rimosso con successo</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Inserisci il nome utente</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Inserisci il nome del gruppo</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Nessun gruppo "%1"</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Già condiviso con %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Già condiviso con l'utente %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>L'operazione precedente è ancora in corso</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Condividi con:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Condividi</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Permessi:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lettura-Scrittura</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>In sola lettura</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Chiudi</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>sincronizzato</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indicizzazione dei documenti</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inizializzazione sincronizzazione</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>scaricamento</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>caricamento</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>fusione sincronia</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>in attesa di sincronizzazione</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>server non connesso</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>autenticazione del server</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>sincronizzazione automatica disattivata</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>sconosciuto</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Errore sconosciuto</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Errore di rete</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>Impossibile risolvere l'indirizzo del proxy</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>Impossibile risolvere l'indirizzo del server</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Impossibile connettersi al server</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Errore del Server</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Memoria insufficiente </translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Limite spazio disponibile raggiunto</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>La liberia è stata cancellata sul server</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Libreria danneggiata sul server</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Lo spazio di archiviazione è esaurito.</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inizializzazione...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>connessione al server...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indicizzazione dei documenti...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Scarico la lista dei file...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Scaricamento dei file...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Creazione cartella...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Unisci i cambiamenti del file..</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Fatto</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>Controllo informazioni del server...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Cancellazione</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Cancellato</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Errore SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Errore di Rete: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Errore del Server</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>Fallita apertura del database certs</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Il file "%1" non esiste all'interno di "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 impossibile trovare un'applicazione per aprire il file %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Creata la libreria "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Cancellata la libreria "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Rinomina %1 come</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Impossibile scaricare "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>copia fallita</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Aggiunto</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Cancellato</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Rimosso</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Modificato</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Rinominato</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Aggiunto o modificato</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Spostato</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Cartella aggiunta</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Cartella rimossa</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Cartella rinominata</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Cartella spostata</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>file</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>percorsi</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>e %1 di più</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Riporta lo stato della libreria a</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Riportato il file "%1" allo stato %2</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Recuperata la directory cancellata</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Modificato il nome della libreria o la descrizione</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Un attimo fa</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 giorno fa</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 giorni fa</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 ora fa</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 ore fa</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 minuto fa</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 minuti fa</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Sincronizza questa libreria in:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Sincronizza questa cartella in:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Cartella</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Cartella in sola lettura</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Documento</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Documento PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Immagine</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Documento di Testo</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>File Audio</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>File Video</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Documento Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Documento PowerPoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Documento Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>caricamento della lista file</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>File bloccato da un altro programma </translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>Cartella bloccata da un altro programma </translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>File bloccato da un altro utente</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Percorso non valido</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Errore durante l'indicizzazione</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>Il percorso termina con uno spazio o una virgola</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>il percorso contiene caratteri non validi come '|' o ':'</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>Errore nell'apertura del database della cache</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>il percorso contiene caratteri non validi come '|' o ':'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>Il file non esiste</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Libreria "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Questa libreria non è ancora stata scaricata</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Errore:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>ogni %1 secondi</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>RepoIcon</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>RepoName</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Etichetta di Testo</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Proprietario:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Ultima Modifica:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Dimensione:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Percorso Locale:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Stato:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>RepoStatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nome:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Intervallo di sincronizzazione:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Chiuso</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Questa libreria non è stata scaricata</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Aggiornamenti Recenti</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Le mie Librerie</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sotto Libreria</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Condivise con me</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Condivise con tutti</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Condivise con il gruppo</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Librerie Sincronizzate</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Avvio sincronizzazione</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Disabilita sincronizzazione automatica</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Abilita sincronizzazione automatica</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Mostra &dettagli</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Mostra dettagli di questa libreria</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Sincronizza questa libreria</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Sincronizza questa libreria</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Aggiornamenti Recenti</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Sincronizza &adesso</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Sincronizza questa libreria immediatamente</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancella download</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Cancella download di questa libreria</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Apri cartella</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>apri cartella locale</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Desincronizza</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>desincronizza questa libreria</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Visualizza sul server</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>visualizza questa libreria su seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Condividi con l'utente</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Condividi questa libreria con un utente</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Condividi con un gruppo</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Condividi questa libreria con un gruppo</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Open vista file in cloud</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>&Leave condivisione</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>lascia la condivisione</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Sincronizza questa libreria</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>de-sincronizza e ri-sincronizza questa libreria</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Fallita desincronizzazione libreria "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Impossibile lasciare la condivisione</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Fallita la cancellazione di questo task:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Questo download è stato cancellato</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Non hai i permessi per caricare in questa cartella</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Impossibile sovrascrivere il file "%1" con se stesso</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Impossibile cancellare il file "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Impossibile caricare il file: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Intervallo di sincronizzazione (in secondi):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Imposta intervallo di sincronizzazione per la libreria "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Cerca librerie</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>riprova</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Tentativo fallito di ottenere informazioni delle librerie<br/>Per favore %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Attenzione:</b> Il certificato ssl di questo server non è affidabile, procedere comunque?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Fallita inizializzazione log: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Si</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 Link Interno</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copia negli appunti</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Errore sconosciuto</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Disabilita sincronizzazione automatica</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Abilita sincronizzazione automatica</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Quit</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Mostra finestra principale</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Impostazioni</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Apri %1 &folder</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>apri la cartella %1</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Apri la cartella dei log</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Mostra errori sincronizzazione</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Informazioni</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Mostra il box About</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Guida in linea</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>File</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>la sincronizzazione automatica è disabilitata</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Caricando</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Scaricando</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>apri la cartella log %1</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>apri la guida in linea di %1</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>alcuni server non sono connessi</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Carica file di log</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>carica il file di log %1</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Per favore prima effettua l'accesso</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Show nella cartella</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Mostra nella cartella</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Cerca file</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>riprova</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Impossibile cercare <br/> prego %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Stato di connessione dei server</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>connesso</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>disconnesso</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Chiudi</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Prego, inserire la password della libreria</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Inserisci la password per la libreria %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Prego, inserisci la password</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Password non corretta</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Errore sconosciuto</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Finestra</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Impostazioni</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Avvia automatico %1 dopo il login</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Nascondi l'icona di %1 dal dock</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Nessuno</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>Proxy HTTP</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Proxy Socks5</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Proxy di sistema</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Hai modificato la lingua. Vuoi riavviare per applicare?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>L'indirizzo del proxy non può essere vuoto</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>La porta del proxy non è corretta</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>L'utente del proxy non può essere vuoto</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>La password del proxy non può essere vuota</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Nascondi la finestra principale dopo l'avvio</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Notifica quando le librerie sono sincronizzate</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Abilita la sincronizzazione dei file temporanei di MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Velocità massima di download (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Velocità massima di caricamento (kB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Base</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Non desincronizzare automaticamente una libreria</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Non desincronizzare automaticamente una libreria quando la sua cartella locale è rimossa o non accessibile per altre ragioni.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Non sincronizzare una libreria quando non nel server</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Non desincronizzare una libreria quando non presente nel server</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Abilita l'estensione FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Abilita l'estensione di Esplora Risorse</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>controlla aggiornamenti automaticamente </translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Non verificare il certificato ssl del server</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Avanzato</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Lingua (richiede riavvio)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Lingua</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Tipo di Proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Host:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Porta:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Nome Utente:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Password:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Il server proxy richiede una password </translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Rete</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancella</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lettura-Scrittura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>In sola lettura</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Rimuovi Condivisione</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Click per modificare</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Creato da %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lettura-Scrittura</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>In sola lettura</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Gruppo</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Utente</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Permessi</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>L'operazione precedente è ancora in corso</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Condividi Link</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Condividi Link:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Download Diretto</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copia negli appunti</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Connessione Non Affidabile</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 utilizza un certificato di sicurezza non valido. La connessione potrebbe essere insicura. Vuoi continuare?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Il fingerprint della chiave corrente RSA è %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Il fingerprint della chiave RSA precedente è %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Ricorda la mia scelta</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sì</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Apri</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Apri questo file</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>Visualizza sul &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>vedi questo file sul sito</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>riprova</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Tentativo fallito di ottenere informazioni dei preferiti<br/>Per favore %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Non hai nessun file preferito.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Errore Sincronizzazione File</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Nessun errore di sincronizzazione. </translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Doppio click per aprire la libreria</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Libreria</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Percorso</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Errore</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Tempo</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Inserire chiave per autenticazione a due fattori</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Autenticazione a due fattori</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Inserire chiave per autenticazione a due fattori</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Ricorda questo dispositivo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annulla</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Disinstalla %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Vuoi elimiare le informazioni dell'account %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Eliminazione delle informazioni dell'account...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>testo</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sì</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>No</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ja" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>アカウントデータベース接続に失敗しました</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>承認タイムアウト、再ログインしてください</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>アカウント設定</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>サーバーアドレスを入力してください</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1のサーバーアドレスは正しくありません</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>アカウント情報の保存に失敗しました</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>%1の情報の保存に失敗しました</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>アカウント情報を保存しました</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>サーバーアドレス</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>メール</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>%1アカウントのライブラリ同期解除に失敗しました</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>クリックでウェブサイトが開きます</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>Pro版</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>アカウント無し</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>アカウント設定</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>アカウントを追加</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>ログアウト</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>ログインはまだ</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>アカウント</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>メール</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>サーバ</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>再実行</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>アップロード完了</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>ファイル%1
+アップロード完了しました。</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>ファイル%1
+アップロード失敗しました。</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>プロフィール画像フォルダ作成に失敗しました</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>ダウンロード・ジョブ</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>完了したジョブを削除</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>今はダウンロードをしない。</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>クリア</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>閉じる</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>ライブラリ</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>パス</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>ジョブをキャンセル</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>ジョブをキャンセル</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>ジョブを削除</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>ジョブのキャンセルに失敗しました:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>ジョブの削除に失敗しました:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>最小にする</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>閉じる</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>ライブラリ</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>同期フォルダを選択してください</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>フォーム</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>ロゴ</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>最小にする</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>閉じる</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>選択</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>ccnet設定でエラーが発生しました</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>ディレクトリを選択してください</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>同期ディレクトリを選択してください</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>名前を入力してください</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>パスワードを入力してください</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>パスワードが一致しません</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>不明なエラー</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>ダウンロードジョブの追加に失敗しました:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>パス:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>選択してください</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>名称:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>パスワード:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>パスワード確認:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>パスワードを入力してください</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>フォルダを選択してください</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>同期フォルダを選択してください</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>ダウンロードジョブの追加に失敗しました:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>選択してください</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>ライブラリのパスワード:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>変更詳細</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>クラウドファイル表示</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>戻る</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>進む</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>ホーム</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>ファイルをアップロード</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>ディレクトリをアップロード</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>フォルダを作成</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>フォルダ名</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>正しくないフォルダ名</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>再実行</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>%1ファイルが既にあります。<br/>上書きして宜しいですか?<br/><small>(別名でアップロードする場合には「いいえ」を選択してください).。</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>アップロードファイルを選択してください</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>アップロードディレクトリを選択してください</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>アップロード</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>アップロード中 %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>ダウンロード</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>ダウンロード中 %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>処理がキャンセルされました</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>サーバ内部エラー</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>名称</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>サイズ</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>名前付け保存(&s)</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>名前変更(&r)</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>削除(&d)</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>更新(&u)</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>コピー(&c)</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>カット(&t)</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>ペスト(&p)</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>ダウンロードキャンセル(&e)</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>フォルダ同期(&s)</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>この機能はPro版のみで利用可能です
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>ディレクトリを選択してください</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>ロゴ</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>選択してください</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>次</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>デフォルト・ライブラリをダウンロード中にエラーが発生しました:%1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>はい</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>ロゴ</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>ネットワークエラー:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>ユーザー名を入力してください</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>コンピュータ名を入力してください</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>パスワードを入力してください</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>メールアドレスまたはパスワードが正しくありません</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>サーバ内部エラー</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>ロゴ</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>パスワード:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>コンピュータ名:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>不明なエラー</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>キャンセル中</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>キャンセルしました</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSLエラー</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>ネットワークエラー:%1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>サーバエラー</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>ファイル</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>只今</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1日前</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1日前</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1時間前</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1時間前</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1分前</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1分前</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>フォルダー</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>ドキュメント</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF・ドキュメント</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>映像ファイル</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>テキスト・ドキュメント</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>音声ファイル</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>動画ファイル</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>ワード・ドキュメント</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>パワーポイント・ドキュメント</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>エクセル・ドキュメント</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>無効なパス</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>"%1"ライブラリ</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>エラー:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>リポジトリ名</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>ローカルパス</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>名称:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>閉じる</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>同期(&n)</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>ダウンロードをキャンセル(&c)</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>ライブラリのダウンロードをキャンセル</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>ジョブのキャンセルに失敗しました:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>ダウンロードがキャンセルされました</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>不明なエラー</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>閉じる</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>ライブラリのパスワードを入力してください</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>%1ライブラリのパスワードを入力してください</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>パスワードを入力してください</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>パスワードが正しくありません</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>不明なエラー</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>なし</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>ユーザー名:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>パスワード:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>プロクシパスワードを入力してください。</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>キャンセル</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>はい</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>いいえ</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>パーズ</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>エラー</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>ダイアログ</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>はい</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>いいえ</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ko_KR" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>%1 정보</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 클라이언트 %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> 리비전 %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>정보</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>업데이트 확인</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>계정 데이터베이스 열기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>인증 유효시간이 지났습니다. 다시 로그인하세요</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>로컬 저장소 동기화 토큰 제거에 실패했습니다: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>서버에서 저장소 동기화 정보 가져오기에 실패했습니다: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>계정 설정</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>서버 주소를 입력해주세요</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 서버 주소가 올바르지 않습니다</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>계정 정보 저장에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>바뀐 내용 저장에 실패했습니다: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>현재 계정 정보 업데이트에 성공했습니다</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>서버 주소</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>전자메일</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>%1 계정을 정말 제거할까요?<br><br>로컬 계정만 삭제합니다. 모든 동기화 정보도 함께 삭제합니다. 서버 계정에는 영향을 주지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>이 계정의 라이브러리 동기화 해제에 실패했습니다: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>웹 사이트를 열려면 클릭하세요</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>전문가 버전</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>계정 없음</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>선택</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>계정 설정</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>로그인</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>삭제</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>계정 추가</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>로그아웃</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>로그인 안 함</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>양식</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>계정</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>전자메일</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>서버</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>파일 활동은 %1 서버 전문가 판에서만 지원합니다.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>다시 시도</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>활동 정보 가져오기에 실패했습니다. %1 해주세요</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>업로드 성공</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>"%1" 파일
+업로드에 성공했습니다.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>"%1" 파일
+업로드에 실패했습니다.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>권한 오류!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>인증 유효 시간이 지났습니다.</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>파일이 없습니다</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>%1이(가) 파일을 잠궜습니다. 나중에 다시 시도하세요</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>업로드 실패: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>아바타 폴더 만들기에 실패했습니다</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>권한 검사 중</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>다운로드 작업</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>성공한 모든 작업 제거</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>현재 다운로드 작업이 없습니다.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>지우기</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>닫기</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>라이브러리</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>경로</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>이 작업 취소</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>이 작업 취소</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>이 작업 제거</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>이 작업 취소에 실패했습니다:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>이 작업 제거에 실패했습니다:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>최소화</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>닫기</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>라이브러리</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>별표 표시함</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>활동</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>검색</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>현재 다운로드율</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>현재 업로드율</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>동기화할 폴더를 선택해주세요</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>연결한 서버 없음</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>모든 서버에 연결했습니다</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>일부 서버에 연결하지 않았습니다</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>양식</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>로고</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>최소화</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>닫기</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>선택</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>브랜드</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>하거나 폴더를 내려놓아 동기화하세요</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>다운로드율</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>아래 화살표</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>업로드율</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>위 화살표</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>ccnet 설정을 만드는데 오류가 있습니다</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>미리 설정한 "%1" 디렉터리를 만들 수 없습니다</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>%1 읽기 실패</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>라이브러리 만들기</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>디렉토리를 선택해주세요</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>만드는 중...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>이 라이브러리의 암호화 키 생성에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>동기화 할 디렉토리를 선택해주세요</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>%1 폴더가 없습니다</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>이름을 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>암호를 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>암호가 일치하지 않습니다</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>알 수 없는 오류</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>다운로드 작업 추가에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>서버에 라이브러리 만들기에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>경로:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>선택</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>이름:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>암호화</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>암호:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>암호 다시입력:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>상태 텍스트</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 클라이언트 초기화에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>예상치 못하게 %1(에)서 빠져나왔습니다</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>암호를 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>"%1" 라이브러리 동기화</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>"%1" 동기화 폴더</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>이 폴더에 동기화:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>또는</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>기존 폴더와 동기화</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>새 동기화 폴더 만들기</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>다음 기존 폴더와 동기화:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>폴더를 선택하세요</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>폴더가 없습니다</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>동기화할 폴더를 선택하세요</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>%1 폴더 밖으로의 라이브러리 위치는 금지되어 있습니다.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>기존의 "%1" 파일이 이미 있습니다. 다른 폴더를 선택하세요.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>기존의 "%1" 라이브러리가 이미 있습니다. 다른 폴더를 선택하세요.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>"%1" 폴더가 이미 있습니다. 정말로 이 폴더를 동기화(내용 병합)할까요?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>아니요를 누르면 새 폴더로 동기화합니다</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>다른 폴더 이름을 찾을 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>다운로드 작업 추가에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>저장소 다운로드 정보 가져오기에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>라이브러리 다운로드</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>선택...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>이 라이브러리 암호:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>자세한 수정 내용</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>추가한 파일</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>삭제한 파일</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>수정한 파일</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>추가한 폴더</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>삭제한 폴더</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>열기(&O)</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>상위 폴더 열기(&P)</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>클라우드 파일 브라우저</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>뒤로</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>앞으로</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>처음</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>파일 업로드</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>디렉터리 업로드</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>이 라이브러리에 파일을 업로드할 권한이 없습니다</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>폴더 만들기</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>새로 고침</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>항목 %1개</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>폴더 이름</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>잘못된 폴더 이름입니다!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>"%1" 이름을 가진 객체가 있습니다.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>다시 시도</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>파일 정보 가져오기에 실패했습니다<br/>
+%1 해주세요</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>이 폴더는 비어있습니다.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>저장할 파일 이름을 입력하세요...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>"%1" 파일을 제거할 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>저장하려는 폴더 경로를 입력하세요...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>기존의 "%1" 파일을 덮어쓸까요?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>"%1" 파일은 동기화하지 않았습니다</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>%1 파일이 존재합니다.<br/>덮어쓸까요?<br/><small>(다른 이름으로 업로드하려면 아니요를 선택하세요).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>파일이 없습니다</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>파일 다운로드에 실패했습니다: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>업로드할 파일을 선택하세요</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>업로드할 디렉터리를 선택하세요</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>이름 바꾸기</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>이 항목을 정말로 삭제할까요?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>폴더 만들기 실패</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>파일 잠금 실패</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>%1을(를) 업데이트할 파일을 선택하세요</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>이름 바꾸기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>제거에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>공유에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>동일한 폴더에 파일을 붙여넣을 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>폴더를 자체 하위 폴더로 붙여넣을 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>복사 실패</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>이동 실패</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>라이브러리 만들기에 실패했습니다!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>이 폴더에 업로드할 권한이 없습니다</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>인증 유효 시간이 지났습니다.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>권한 오류!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>라이브러리/폴더가 없습니다.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>%1 파일 업로드에 실패했습니다: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>캐시 폴더를 만들 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>캐시 폴더를 열 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>파일 검색</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>링크 가져오기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>대기 중</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>업로드</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>%1 업로드 중</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>다운로드</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>%1 다운로드 중</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%2 중 %1</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>"%1" 파일 업로드에 실패했습니다. 다시 시도해볼까요?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>다시 시도</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>건너뛰기</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>중단</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>저장 중</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>파일 저장에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>인덱싱 진행 요청 오류 %1</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>이름</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>크기</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>마지막 수정</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>폴더에 표시(&S)</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>폴더에 표시</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>동작을 취소했습니다</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>기다리는 중</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>작업을 취소했습니다</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>내부 서버 오류</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>제한 저장 공간을 모두 채웠습니다</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>%1이(가) 잠금</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>이름 </translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>크기</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>마지막 수정</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>수정자</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>다른 이름으로 저장(&S)...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>잠금(&L)</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>제거(&R)</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>삭제(&D)</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>그룹에 공유</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>업데이트(&U)</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>복사(&C)</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>잘라내기(&T)</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>붙여넣기(&P)</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>다운로드 취소(&E)</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>이 폴더 동기화(&S)</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>이 기능은 전문가 버전에서만 사용할 수 있습니다
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>%1 다운로드 링크 만들기(&G)</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>사용자에게 공유</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>%1 내부 링크 만들기(&E)</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>다음 경로에 다른 이름으로 저장(&S)...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>잠금 해제(&L)</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>읽기 전용 파일을 제거할 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>읽기 전용 파일을 잘라낼 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>업로드 다시 시도</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>로컬 버전 삭제</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>로컬 버전을 다른 이름으로 저장...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>로컬 캐시 폴더 열기</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>폴더 만들기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>임시 파일 만들기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>디스크로의 파일 기록에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>다운로드한 파일의 이전 버전 삭제에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>파일 이동에 실패했습니다</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 초기화</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>%1 폴더 선택</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>디렉토리를 선택해주세요</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>초기화를 끝내지 않았습니다. 정말 빠져나갈까요?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>%1 폴더가 없습니다</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>로고</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>폴더 선택</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>폴더를 선택하세요. %1 하위 폴더를 만들겠습니다. 라이브러리를 다운로드하면 기본으로 해당 위치에 저장합니다.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>선택...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>다음</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 에서 라이브러리로 파일을 모아둡니다.
+기본 라이브러리를 다운로드할까요?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>기본 라이브러리 확인 중...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>기본 라이브러리 만드는 중...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>기본 라이브러리 만들기에 실패했습니다:
+
+이를 지원하려면 서버버전은 2.1 이상이어야 합니다.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>기본 라이브러리 가져오기에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>기본 라이브러리 만들기에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>기본 라이브러리 다운로드 중...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>기본 라이브러리 다운로드에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>기본 라이브러리를 다운로드했습니다.
+"열기"버튼을 눌러 다운로드한 내용을 보실 수 있습니다.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>기본 라이브러리 다운로드 중 오류: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>기본 라이브러리 다운로드에 실패했습니다:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 에서 라이브러리로 파일을 모아둡니다.
+기본 라이브러리를 다운로드할까요?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>건너뛰기</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>백그라운드에서 실행</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>열기</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>끝내기</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>기본 라이브러리 다운로드</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>예</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>로고</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>더 불러오기</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>실패 로그 파일 업로드</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>로그 파일 업로드</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>권한 오류!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>라이브러리/폴더가 없습니다.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>인증 유효 시간이 지났습니다.</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>로그 파일 업로드 실패: %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>로그 파일 업로드에 성공했습니다</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>압축 중</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%2 중 %1</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>계정 추가</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>단일 로그온</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>다시 로그인</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>로그인 중...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>네트워크 오류:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>경고:</b> 이 서버의 ssl 인증서를 믿을 수 없습니다, 그래도 진행할까요?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>서버 주소를 입력해주세요</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 서버 주소가 올바르지 않습니다</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>사용자 이름을 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>컴퓨터 이름을 입력해주세요</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 서버 주소</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>서버 주소를 비워둘 수 없습니다</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1은(는) 올바른 서버 주소가 아닙니다. 'https://'로 시작해야 합니다</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>암호를 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>전자메일 주소 또는 암호가 틀렸습니다</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>로깅을 너무 자주 합니다, 잠시만 기다려주세요</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>내부 서버 오류</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>로그인 실패: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>로그인에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>로고</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>서버:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>예: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>또는 http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>암호:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>상태 텍스트</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>컴퓨터 이름:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>전자메일 / 사용자 이름</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>e.g. 철수의 랩톱</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>로그인</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>자동 로그인</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>로그아웃 했습니다.</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>로그인해주세요</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>계정 추가</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>새로고침</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>"%1"을(를) 동기화했습니다.</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>"%1"에 파일을 업로드했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>%1 파일 동기화에 실패했습니다
+다른 프로그램에서 파일을 잠궜습니다. 프로그램을 닫으면 이 파일을 업데이트합니다.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>%1 폴더 동기화에 실패했습니다
+폴더의 일부 파일을 다른 프로그램에서 잠궜습니다. 프로그램을 닫으면 이 폴더를 업데이트합니다.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>%1 파일 동기화에 실패했습니다
+다른 사용자가 파일을 잠궜습니다. 이 파일의 최신 버전을 업로드하지 않았습니다.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>%1 파일 인덱싱에 실패했습니다.
+파일 권한과 디스크 공간을 확인하세요.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>%1 동기화에 실패했습니다
+파일 경로끝에 공백 문자 또는 구두점이 있으며, 윈도우에서 만들 수 없습니다.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>%1 동기화에 실패했습니다
+파일 경로에 부적절한 문자가 있습니다. 이 컴퓨터에 동기화하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>폴더 권한 설정에 따라 %1 파일 업데이트를 거부합니다.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>%1 폴더 동기화 권한이 없습니다.</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>%1 공유</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>그룹 이름을 입력하세요</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>사용자 이름 또는 전자메일 주소를 입력하세요</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>성공적으로 업데이트했습니다</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>공유 처리에 실패했습니다: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>성공적으로 제거했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>폴더의 공유 정보 가져오기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>그룹 및 연락처 정보 가져오기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>사용자 이름을 입력하세요</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>그룹 이름을 입력하세요</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>"%1" 그룹이 없습니다</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>%1 그룹에 이미 공유했습니다</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>%1 사용자에게 이미 공유했습니다</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>이전 처리를 여전히 진행중입니다</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>공유 대상:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>공유</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>권한:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>읽기-쓰기</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>읽기 전용</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>닫기</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>동기화 함</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>파일 색인 중</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>동기화 초기화 중</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>다운로드 중</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>업로드 중</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>동기화 병합 중</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>동기화 기다리는 중</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>연결한 서버가 없습니다.</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>서버 인증 중</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>자동 동기화를 껐습니다</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>알 수 없음</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>알 수 없는 오류</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>네트워크 오류</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>프록시 주소를 해석할 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>서버 주소를 해석할 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>서버에 연결할 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>보안 연결에 실패했습니다. 서버 SSL 인증서를 확인하세요</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>데이터 전송을 멈췄습니다. 네트워크 또는 방화벽을 확인하세요</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>데이터 전송 시간을 초과했습니다. 네트워크 또는 방화벽을 확인하세요</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>서버에서 처리할 수 없는 http 경로 변경. 서버 설정을 확인하세요</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>서버 오류</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>메모리 부족</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>클라이언트 데이터 기록에 실패했습니다. 디스크 공간 또는 폴더 권한을 확인하세요</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>저장 공간이 찼습니다</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>서버의 라이브러리를 삭제했습니다</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>서버의 라이브러리가 깨졌습니다</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>저장공간 제한을 채웠습니다</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>초기화 중...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>서버에 연결 중...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>파일 색인 중</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>파일 목록 다운로드 중...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>파일 다운로드 중...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>폴더 만드는 중...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>바뀐 파일 병합 중...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>완료</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>서버 정보 확인 중...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>취소 중</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>취소함</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL 오류</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>네트워크 오류: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>서버 오류</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>cert 데이터베이스 열기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>"%2"에 "%1" 파일이 없습니다</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1이(가) %2 파일을 열 프로그램을 찾을 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>"%1" 라이브러리를 만들었습니다</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>"%1" 라이브러리를 삭제했습니다</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>%1 이름 바꾸기:</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>"%1" 항목을 다운로드할 수 없습니다</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>복사에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>추가함</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>삭제함</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>제거함</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>수정함</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>이름 바꿈</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>추가 또는 수정함</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>이동함</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>추가한 디렉터리</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>제거한 디렉터리</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>이름 바꾼 디렉터리</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>이동한 디렉터리</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>파일</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>디렉터리</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>및 추가 %1개 </translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>다음 시간의 상태로 라이브러리 복원:</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>"%1" 파일을 %2의 상태로 복원했습니다.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>삭제한 디렉터리를 복구했습니다</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>라이브러리 이름 또는 설명을 바꾸었습니다</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>%1 시스템에서 자동으로 병합</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>방금</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1일 전</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1일 전</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1시간 전</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1시간 전</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1분 전</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1분 전</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>이 라이브러리 동기화 대상:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>이 폴더 동기화 대상:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>폴더</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>읽기 전용 폴더</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>문서</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF 문서</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>그림 파일</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>텍스트 문서</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>오디오 파일</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>동영상 파일</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>워드 문서</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>파워포인트 문서</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>엑셀 문서</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>"%1" 경로가 시스템 경로와 충돌합니다</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>"%1" 경로가 기존 라이브러리와 충돌합니다</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>파일 목록 업로드 중</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>다른 프로그램에서 파일을 잠궜습니다</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>다른 프로그램에서 폴더를 잠궜습니다</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>다른 사용자가 파일을 잠궜습니다</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>잘못된 경로</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>인덱싱 오류</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>경로 끝에 공백 또는 마침표가 있습니다</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>경로에 '|' 또는 ';' 같은 잘못된 문자가 있습니다</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>파일 캐시 데이터베이스 열기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>':', '*', '|', '?' 같은 잘못된 문자가 라이브러리 이름에 있습니다</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>폴더 권한 설정에 따라 파일 업데이트를 거부합니다</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>%1 클라이언트를 이미 실행 중입니다</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>클라이언트 내부 데이터가 깨졌습니다. 라이브러리를 다시 동기화해보세요</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>라이브러리 기록 권한이 없습니다</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>이 폴더를 동기화할 권한이 없습니다</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>휴지통의 모든 항목을 제거했습니다</translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>휴지통에서 %1일이 지난 항목을 제거했습니다</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>공개 초안</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>만든 초안</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>만든 파일</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>이름 바꾼 파일</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>삭제한 초안</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>삭제한 파일</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>복원한 파일</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>옮긴 파일</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>업데이트한 파일</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>만든 폴더</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>이름 바꾼 폴더</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>삭제한 폴더</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>복원한 폴더</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>이동한 폴더</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>만든 라이브러리</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>이름 바꾼 라이브러리</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>삭제한 라이브러리</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>복원한 라이브러리</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>파일이 없습니다</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>"%1" 라이브러리</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>이 라이브러리를 아직 다운로드하지 않았습니다</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>오류:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>%1 초 마다</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>저장소 아이콘</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>저장소 이름</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>텍스트 레이블</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>소유자:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>최종 고침:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>크기:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>로컬 경로:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>상태:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>저장소 상태</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>이름:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>동기화 시간 간격:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>닫기</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>이 라이브러리는 다운로드하지 않았습니다</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>없는 "%2" 라이브러리의 "%1" 파일을 열 수 없습니다</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>최근 업로드</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>내 라이브러리</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>하위 라이브러리</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>나에게 공유</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>모두에게 공유</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>그룹에 공유</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>동기화한 라이브러리</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>동기화 초기화 중</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>자동 동기화 비활성화</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>자동 동기화 활성화</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>세부 정보 표시(&D)</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>이 라이브러리 세부 정보 표시</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>이 라이브러리 동기화(&S)</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>이 라이브러리 동기화</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>최근 업데이트 항목</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>지금 동기화(&N)</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>이 라이브러리 바로 동기화</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>다운로드 취소(&C)</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>이 라이브러리 다운로드 취소</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>폴더 열기(&O)</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>로컬 폴더 열기</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>로컬 폴더 열기(&O)</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>동기화 해제(&U)</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>이 라이브러리 동기화 해제</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>클라우드에서 보기(&V)</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>시허브에서 이 라이브러리 보기</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>사용자에게 공유</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>이 라이브러리를 사용자에게 공유합니다</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>그룹에 공유</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>이 라이브러리를 그룹에 공유합니다</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>클라우드 파일 브라우저 열기(&O)</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>내장 클라우드 파일 브라우저에서 이 파일을 엽니다</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>공유 항목에서 나가기(&L)</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>공유 항목에서 나가기</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>이 라이브러리 다시 동기화(&R)</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>이 라이브러리 동기화를 해제하고 다시 동기화합니다</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>동기화 시간 간격 설정(&I)</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>이 라이브러리 동기화 주기 설정</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>"%1" 라이브러리 동기화를 해제할까요?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>"%1" 라이브러리를 다시 동기화할까요?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>"%1" 파일을 덮어쓸까요?</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>"%1" 라이브러리 동기화 해제에 실패했습니다.</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>"%1" 공유에서 나갈까요?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>공유 항목에서 나가기에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>이 작업 취소에 실패했습니다:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>다운로드를 취소했습니다.</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>이 폴더에 업로드할 권한이 없습니다</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>"%1" 파일 자체에 덮어쓸 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>"%1" 파일을 삭제할 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>파일 업로드에 실패했습니다: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>동기화 시간 간격(초 단위):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>"%1" 라이브러리 동기화 시간 간격을 설정합니다</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>라이브러리 검색</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>다시 시도</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>라이브러리 정보를 가져오는데 실패했습니다<br/>%1 해주세요</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>경고:</b> 이 서버의 ssl 인증서를 믿을 수 없습니다, 그래도 진행할까요?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>로그 초기화에 실패했습니다: %1</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>예</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>아니요</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>클라이언트 ID 저장 실패</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>%1 접근 실패</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>올바르지 않은 클라이언트 ID</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>%1 읽기 실패</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 내부 링크</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>클립보드로 복사</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>%1 내부 링크:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>알 수 없는 오류</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>내부 오류: 데몬 연결 실패</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>자동 동기화 비활성화</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>자동 동기화 활성화</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>끝내기(&Q)</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>메인 창 표시</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>설정</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>%1 폴더 열기(&F)</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>%1 폴더 열기</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>기록 폴더 열기(&L)</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>파일 동기화 오류 표시</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>정보(&A)</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>프로그램 정보 상자 표시</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>온라인 도움말(&O)</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>파일</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>자동 동기화를 비활성화했습니다</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>업로드 중</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>다운로드 중</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>%1 기록 폴더 열기</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>%1 온라인 도움말 열기</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>일부 서버에 연결하지 않았습니다</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>로그 파일 업로드</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>로그 파일 %1개 업로드</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>먼저 로그인 해주세요</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>탐색기 확장 기능 복원</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>탐색기의 동기화 상태 아이콘 수정에 성공했습니다</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>탐색기의 동기화 상태 아이콘 수정에 실패했습니다</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>폴더에 표시(&S)</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>폴더에 표시</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>파일 검색</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>다시 시도</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>검색에 실패했습니다.
+%1 해주세요</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>서버 연결 상태</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>연결함</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>연결 끊음</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>닫기</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>라이브러리 암호를 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>%1 라이브러리의 암호를 입력하세요</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>암호를 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>올바르지 않은 암호</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>알 수 없는 오류</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화 상자</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>설정</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>로그인 후 %1 자동 시작</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>도크에서 %1 아이콘 숨기기</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>없음</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP 프록시</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 프록시</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>시스템 프록시</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>언어를 바꿨습니다. 다시 시작해서 적용할까요?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>프록시 호스트 주소를 비워둘 수 없습니다</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>프록시 포트가 올바르지 않습니다</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>프록시 사용자 이름을 비워둘 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>프록시 암호를 비워둘 수 없습니다</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>시작할 때 메인 창 숨기기</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>라이브러리를 동기화하면 알림</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>MS 오피스/리브레오피스 임시 파일 동기화 활성화</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>다운로드 속도 제한(KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>업로드 속도 제한(KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>기본</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>자동으로 라이브러리 동기화 해제 안함</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>로컬 디렉터리를 제거했거나 다른 이유로 접근할 수 없을 때 라이브러리를 자동으로 동기화 해제하지 않습니다.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>서버에 라이브러리가 없으면 동기화 해제 안함</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>서버에 라이브러리가 없다면 자동으로 동기화 해제 안함</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>FinderSync 확장 기능 활성화</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>탐색기 확장 기능 활성화</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>업데이트 자동으로 확인</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>HTTPS 동기화시 서버 인증서 검증하지 않음</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>다른 이름을 가진 기존 폴더와 동기화 활성화</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>고급</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>언어(다시 시작해야 함)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>언어</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>프록시 형식:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>호스트:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>포 트:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>사용자 이름:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>암호:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>프록시 서버에 암호가 필요합니다</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>네트워크</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>읽기 쓰기</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>읽기 전용</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>공유 항목 제거</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>눌러서 편집</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>%1 사용자가 만듬</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>읽기 쓰기</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>읽기 전용</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>그룹</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>사용자</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>권한</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>이전 진행 작업을 여전히 처리중입니다</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>연결 공유</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>연결 공유:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>직접 다운로드</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>클립보드로 복사</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>믿을 수 없는 연결</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1이 잘못된 보안 연결을 사용합니다. 연결이 안전하지 않을 수 있습니다. 계속할까요?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>현재 RSA 지문키는 다음과 같습니다: %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>이전 RSA 지문키는 다음과 같습니다: %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>내 선택 기억</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>예</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>아니요</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>열기(&O)</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>이 파일 열기</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>웹에서 보기(&W)</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>웹 사이트에서 이 파일 보기</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>다시 시도</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>별표 표시한 파일 정보 가져오기에 실패했습니다<br/> %1 해주세요</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>아직 별표 표시한 파일이 없습니다.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>파일 동기화 오류</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>오류 없이 동기화했습니다.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>라이브러리를 열려면 두 번 누르세요</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>라이브러리</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>경로</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>오류</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>시간</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>이중 인증 토큰을 입력하세요</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>이중 인증</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>이중 인증 토큰을 입력해주세요</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>이 장치 기억</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>취소</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>확인</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>%1 설치 제거</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>%1 계정 정보를 제거할까요?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>계정 정보 제거 중...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>대화상자</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>텍스트</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>예</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>아니요</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="lv" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Par %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Par</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Meklēt atjauninājumus</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>neizdevās atvērt kontu datubāzi</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Konta iestatījumi</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Lūdzu, ievadiet servera adresi</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 nav derīga servera adrese</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Neizdevās saglabāt konta informāciju</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Neizdevās saglabāt izmaiņas: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Veiksmīgi atjaunināta pašreizējā konta informācija</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Servera adrese</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-pasts</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>pro versija</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Nav konta</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Izvēlēties</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Konta iestatījumi</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Pieslēgties</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Dzēst</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Pievienot kontu</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Atteikties</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Konts</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>e-pasts</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>serveris</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>atkārtot</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Augšupielāde veiksmīga</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Lejupielādēt uzdevumus</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Notīrīt</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Aizvērt</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Bibliotēka</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ceļš</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Atcelt šo uzdevumu</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>atcelt šo uzdevumu</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Dzēst šo uzdevumu</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Neizdevās atcelt šo uzdevumu:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Neizdevās dzēst šo uzdemumu:
+
+ %1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimizēt</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Aizvērt</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotēkas</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favorīti</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation> Aktivitātes</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Meklēt</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>pašreizējais lejupielādes ātrums</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>pašreizējais augšupielādes ātrums</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Forma</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>emblēma</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimizēt</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>aizvērt</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Atlasīt</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>lejupielādes ātrums</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>augšupielādes ātrums</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>neizdevās nolasīt %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Izveidot bibliotēku</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Izveido...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Lūdzu, ievadiet vārdu</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lūdzu, ievadiet paroli</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Paroles nesakrīt</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nezināma kļūda</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Ceļš: </translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Izvēlēties</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Vārds: </translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>šifrēts</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Parole: </translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Parole vēlreiz: </translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>statusa teksts</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lūdzu, ievadiet paroli</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sinhronizēt bibliotēku "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Sinhronizēt mapi "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>vai</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Lūdzu, izvēlieties mapi</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Mape neeksistē</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Lejupielādēt bibliotēku</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>izvēlieties...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Parole šai bibliotēkai:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Izmaiņu detaļas</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Pievienot datnes</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Dzēst datnes</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Modificēt datnes</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Pievienot mapes</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Dzēst mapes</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Atvērt</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Atpakaļ</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Uz priekšu</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Mājas</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Augšupielādēt datnes</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Augšupielādēt mapes</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Izveidot mapi</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Atjaunot</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Mapes vārds</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Mapes vārds nederīgs!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Vārds "%1" ir jau aizņemts.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>atkārtot</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Neizdevās lejupielādēt failu: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Pārdēvēt</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Izveidot mapi neizdevās</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Bloķēt failu neizdevās</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Pārsaukt neizdevās</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Koplietot neizdevās</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kopēt neizdevās</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Pārvietot neizdevās</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Izveidot bibliotēku neizdevās!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Augšupielādēt</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Augšupielādē %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Lejupielādēt</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Lejupielādē %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 no %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operācija atcelta</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>gaida izpildi</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Iekšējā servera kļūda</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>Bloķējis %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Vārds</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Izmērs</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Pēdējoreiz modificēts</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>Pārdēvēt</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>Dzēst</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>Atjaunot</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>Kopēt</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Izgriezt</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>Ielīmēt</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Neizdevās izveidot mapes</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Neizdevās izveidot pagaidu datnes</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Neizdevās ierakstīt datni diskā</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Neizdevās pārvietot datni</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 inicializēšana</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Lūdzu, izvēlieties mapi</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>emblēma</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Izvēlieties mapi</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Izvēlēties...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Nākošais</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Izlaist</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Izpildīt fonā</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Atvērt</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Pabeigts</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Lejupielādēt noklusēto bibliotēku</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Jā</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>emblēma</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Pievienot kontu</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Piesakos...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Tīkla kļūda:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lūdzu, ievadiet paroli</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Iekšējā servera kļūda</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Neizdevās pieteikties: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Neizdevās pieteikties</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>emblēma</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Serveris: </translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Piemēram: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>vai http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Parole: </translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>statusa teksts</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Datora vārds: </translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>E-pasts/Lietotajvārds</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>, piemēram, Džima klēpjdators</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Pieslēgties</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>pieslēgties</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Pievienot kontu</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Atjaunot</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Koplietot %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Aizvērt</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>lejupielādē</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>augšupielādē</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>nezināms</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nezināma kļūda</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicializēšana...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Izveido mapi...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL kļūda</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Tīkla kļūda: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Servera kļūda</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Izveidota bibliotēka "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Dzēsta bibliotēka "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Pārsaukt %1 uz</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>kopēt neizdevās</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Pievienots</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Dzēsts</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Noņemts</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Modificēts</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Pārdēvēts</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Pārvietots</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Pievienota mape</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Noņemta mape</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Pārsaukta mape</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Pārvietota mape</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>datnes</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>mapes</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>un %1 vairāk</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Tagad</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>Pirms 1 dienas</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>Pirms %1 dienām</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>Pirms 1 stundas</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>Pirms %1 stundām</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>Pirms 1 minūtes</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>Pirms %1 minūtēm</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Mape</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Tikai lasāma mape</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Dokuments</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF dokuments</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Attēla datne</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Teksta dokuments</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Audio datne</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Video datne</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word dokuments</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint dokuments</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel dokuments</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Bibliotēka "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Kļūda: </translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>katras %1 sekundes</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Īpašnieks: </translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Pēdējoreiz modificēts:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Izmērs: </translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Lokālais ceļš: </translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Statuss: </translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Bibliotēkas statuss</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Vārds: </translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Aizvērt</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Manas bibliotēkas</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Apakšbibliotēkas</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>Atcelt lejupielādi</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>Atvērt mapi</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>atkārtot</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Jā</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nē</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopēt uz starpliktuvi</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nezināma kļūda</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Iziet</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Iestatījumi</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Par</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>Tiešsaistes palīdzība</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Datne</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Augšupielādē</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Lejupielādē</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>atkārtot</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Servera savienojuma statuss</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>savienots</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>atvienots</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Aizvērt</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lūdzu, ievadiet paroli</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Nepareiza parole</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nezināma kļūda</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Iestatījumi</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Neviens</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP starpniekserveris</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 starpniekserveris</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Lejupielādes ātruma limits (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Augšupielādes ātruma limits (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Pamata</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Uzlabot</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Valoda (nepieciešama pārlāde)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Valoda</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Starpniekservera tips</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Ports:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Lietotājvārds:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Parole: </translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Starpniekserveris prasa paroli</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Tīkls</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Atcelt</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lasīt/Rakstīt</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Tikai lasāms</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lasīt/Rakstīt</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Tikai lasāms</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Grupa</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Lietotājs</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Atļauja</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Koplietot saiti</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopēt uz starpliktuvi</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Labi</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Neuzticams savienojums</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Atcerēties manu izvēli</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Jā</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nē</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Atvērt</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Atvērt datni</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>skatīt &tīmeklī</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>Skatīt datni tīmeklī</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>atkārtot</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Bibliotēka</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Kļūda</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Laiks</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Atinstalēt %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Noņemt konta informāciju...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoga logs</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>teksts</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Jā</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nē</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="nb_NO" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>Mislykkes i å åpne kontoens database</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Innlogging utløpt, logg inn på nytt</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Kontoinnstillinger</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Skriv inn serveradressen</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 er ikke en gyldig serveradresse</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Mislykkes i å lagre kontoinformasjonen</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Mislykkes med å lagre endringene: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Oppdateringen av kontoinformasjonen gikk bra.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Serveradresse</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-post</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Kunne ikke frakoble synkroniseringen av denne kontoen: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>klikk for å åpne websiden</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>pro versjon</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Ingen konto</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Velg</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Konto innstillinger</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Logg inn</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Slette</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Legg til en konto</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>logg ut</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>ikke logget inn</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulær</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Konto</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>epost</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>server</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>prøv på nytt</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Mislyktes i å få aktivitets-informasjon. Vennligst 1%</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Opplasting fulført</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Filen "%1"
+ble lastet opp.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Fil "%1"
+opplasting mislyktes</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Feilet i å generere en avatar folder</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Nedlastings-oppgaver</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>fjern alle gjennomførte oppgaver</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Ingen nedlasting-oppgaver akkurat nå</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Fjern</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Lukk</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Bibliotek</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Sti</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Avslutt denne oppgaven</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>avslutt denne oppgaven</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Fjern denne oppgaven </translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Mislyktes i å avslutte denne oppgaven:
+
+%1 </translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Mislyktes i å fjerne denne oppgaven:
+
+ </translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimalisere</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Lukke</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotek</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Stjerne merket</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Aktiviteter</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Søk</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>nåværende nedlastings-hastighet</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>nåværende opplastings-hastighet</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Vennligst lukk en folder for å synce</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>ingen server er tilknyttet</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>alle servere tilkoblet</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>noen servere er ikke tilkoblet</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulær</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimalisere</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>lukk</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Velg</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>alternativt slipp en folder for å synkronisere</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>nedlastings-hastighet</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>nedover-pil</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>opplastings-hastighet</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>oppover-pil</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Feil ved oppretting av ccnet konfigurason</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Kan ikke opprette forhåndskonfigurert mappe "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>mislyktes i å lese %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Opprett et bibliotek</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Vennligst velg en mappe</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Oppretter...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Klarte ikke å opprette krypteringsnøkkel for dette biblioteket</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Vennligst velg katalogen som skal synkroniseres</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Mappen %1 finnes ikke</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Skriv inn navnet</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Skriv inn passord</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Passordene stemmer ikke overens</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ukjent feil</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Kunne ikke legge til nedlastingsoppgave:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Kunne ikke opprette bibliotek på serveren:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Sti:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Velg</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Navn:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>kryptert</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Passord:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Gjenta passordet:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>status tekst</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Skriv inn passordet</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Synkroniser biblioteket "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Synkroniser mappe "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Synkroniser til mappe:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>eller</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>synkroniser med en eksisterende mappe</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>opprett en ny synkronisert mappe</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Synkroniser med eksisterende mappe:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Velg en mappe</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Mappen finnes ikke</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Velg mappen du vil synkronisere</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Din organisasjon tillater ikke å legge et bibliotek utenfor %1 mappe.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Konflikt med eksisterende fil "%1". Vennligst velg en annen mappe.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Konflikt med eksisterende bibliotek "%1", Vennligst velg en annen mappe.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Mappen "%1" eksisterer allerede. Er du sikker på at du ønsker å synkronisere med den? (innhold vil bli slått sammen)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Trykk nei for å synkronisere med en annen mappe isteden</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Kan ikke finne et alternativt mappenavn</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Kunne ikke legge til nedlastingsoppgaven:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Kunne ikke hente nedlastingsinformasjon fra lokalt kodelager:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Nedlastingsbibliotek</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>velg...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Passord for dette biblioteket:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Endringsinformasjon</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Nye filer</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Slettede filer</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Endrede filer</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Nye mapper</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Slettede mapper</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Åpne</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Cloud filbehandler</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Tilbake</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Fremover</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Hjem</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Last opp filer</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Last opp et bibliotek</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Du har ikke tillatelse til å laste opp filer i dette biblioteket</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Opprett en mappe</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Mappenavn</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Ugyldig mappenavn!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Navnet "%1" er allerede i bruk.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>prøv på nytt</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Kunne ikke hente filinformasjon<br/>Vennligst %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Skriv navnet på filen å lagre til...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Kunne ikke fjerne filen "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Filen %1 eksisterer allerede.<br/>Ønsker du å overskrive den?<br/><small>(Velg "nei" for laste opp med et annet navn).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Kunne ikke laste ned filen: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Velg en fil å laste opp</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Velg en mappe å laste opp</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Omdøpe</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Vil du virkelig slette disse elementene</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Kunne ikke opprette mappe</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Velg en fil å oppdatere %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Kunne ikke omdøpe</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Kunne ikke fjerne</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Kunne ikke dele</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Kan ikke lime inn filer fra samme mappe</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kunne ikke kopiere</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Kunne ikke flytte</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Kunne ikke opprette bibliotek!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Last opp</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Laster opp %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Last ned</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Laster ned %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 av %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Avbrutt operasjon</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>venter</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Intern serverfeil</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Navn</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Størrelse</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Sist endret</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Lagre som...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Omdøpe</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Slett</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Oppdater</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Kopiere</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Kl&ipp ut</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Lim inn</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Av&bryt nedlasting</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Synkroniser mappen</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Denne funksjonen er bare tilgjengelig i Pro-utgaven
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Kunne ikke opprette mapper</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Kunne ikke opprette midlertidige filer</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Kunne ikke skrive filen til disk</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Kunen ikke fjerne tidligere versjon av den nedlastede filen</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Kunne ikke flytte filen</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Initialisering</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Vennligst velg en mappe</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Initialisering er ikke fullført. Vil du virkelig avslutte?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Mappen %1 eksisterer ikke</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Velg...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Neste</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Kontrollerer ditt standard bibliotek...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Oppretter standardbiblioteket...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Kunne ikke opprette standardbiblioteket:
+
+Serverversjonen må være 2.1 eller høyere for å støtte dette.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Kunne ikke hente standard bibliotek:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Kunne ikke opprette standard bibliotek:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Laster ned standard bibliotek...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Kunne ikke laste ned standard bibliotek:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Standardbiblioteket er lastet ned.
+Du kan trykke på "åpne"-knappen for å se på det.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Kunne ikke laste ned standard bibliotek: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Kunne ikke laste ned standard bibliotek:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Hopp over</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Kjør i bakgrunnen</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Åpne</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Avslutte</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Last ned standard bibliotek</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Legg til en konto</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Logg inn pånytt</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Logger inn...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Nettverksfeil:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Advarsel:</b> SSL-sertifikatet på denne serveren er ikke bekreftet, fortsett likevel?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Skriv inn serveradressen</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 er en ugyldig serveradresse</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Skriv inn brukernavnet</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Skriv inn datamaskinnavnet</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Skriv inn passordet</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Feil e-postadresse eller passord</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Du har forsøkt å logge inn for ofte. Vennligst vent et minutt.</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Intern serverfeil</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Kunne ikke logge inn: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Kunne ikke logge inn</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Server:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>For eksempel: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>eller http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Passord:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>status tekst</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Datamaskinnavn:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>for eksempel Ola's bærbare</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Logg inn</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Oppfrisk</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>synkronisert</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indekserer filer</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>synkronisering initialieres</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>laster ned</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>Laster opp</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>synkroniseringen sammenstilles</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>venter på synkronisering</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>serveren er ikke tilkoblet</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>serveren autentiseres</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>automatisk synkronisering er avslått</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>ukjent</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ukjent feil</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Tildelt lagringsplass er oppbrukt</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Initialiserer....</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>kobler til server...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indekserer filer...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Oppretter mappe ....</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Slår sammen filendringer...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Utført</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Avbryter</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Avbrutt</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL-feil.</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Nettverksfeil: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Serverfeil</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>kunne ikke åpne sertifikatdatabasen</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 kunne ikke finne en applikasjon til å åpne filen %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Opprettet biblioteket "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Slettet bibliteket "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Omdøpe %1 til</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Kunne ikke laste ned elementet "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>Kunne ikke kopiere</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Lagt til</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Slettet</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Fjernet</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Endret</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Omdøpt</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Flyttet</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Nytt bibliotek</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Fjernet bibliotek</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Omdøpt bibliotek</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Flyttet bibliotek</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>filer</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>mapper</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>og %1 flere</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Tilbakestilte biblioteket til statusen</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Tilbakestilte filen"%1" til statusen %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Gjenopprettet slettet bibliotek</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Endret biblioteksnavn eller beskrivelse</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Akkurat nå</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 dag siden</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 dager siden</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 time siden</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 timer siden</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 minutt siden</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 minutter siden</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Ikke en del av sertifikatet></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Bibliotek "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Dette biblioteket er ikke lastet ned enda</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Feil: </translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Kodelagerikon</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Kodelagernavn</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Tekstetikett</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Eier:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Sist endret:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>endringstid</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Størrelse:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Lokal sti:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Status:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Kodelagerstatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Navn:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Lukke</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Dette biblioteket har ikke blitt lastet ned</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Nylig oppdatert</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Mine biblioteker</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Underbiblioteker</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Synkroniserte biblioteker</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Slå av automatisk synkronisering</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Slå på automatisk synkronisering</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Vis &detaljer</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Vis bibliotekets detaljer</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Synkroniser dette biblioteket</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Synkroniser dette biblioteket</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Nylig oppdatert</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Synkroniser &nå</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Synkroniser dette biblioteket umiddelbart</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Avbryt nedlasting</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Avbryt nedlastingen av dette biblioteket</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Åpne mappe</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>åpne lokal mappe</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&frakoble synkronisering</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Frakoble synkroniseringen av dette biblioteket</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Se i nettskyen</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>se dette biblioteket på seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Åpne Cloud filbehandleren</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>åpne dette biblioteket i den innebygde Cloud filbehandleren</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Synkroniser dette biblioteket pånytt</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>frakoble og synkroniser dette biblioteket pånytt</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Kunne ikke frakoble synkroniseringen av bibliotek "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Kunne ikke avbryte denne oppgaven:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Nedlastingen har blitt avbrutt</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Kunne ikke slette filen "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Kunne ikke laste opp filen: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>prøv på nytt</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Kunne ikke hente biblioteksinformasjonen<br/>Vennligst %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Advarsel:</b> SSL-sertifikatet på denne serveren er ikke bekreftet, fortsett likevel?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Kunne ikke initialisere loggen: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ukjent feil</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Slå av automatisk synkronisering</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Slå på automatisk synkronisering</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Avslutt</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Vis hovedvindu</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Innstillinger</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Åpne &loggmappen</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Om</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Vis applikasjonens "om" boks</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Hjelp på nett</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Fil</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>automatisk synkronisering er avslått</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Laster opp</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Laster ned</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>noen servere er ikke tilkoblet</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Servernes tilkoblingsstatus</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>tilkoblet</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>frakoblet</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Lukke</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Skriv inn bibliotekspassord</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Skriv inn passordet for bibliotek %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Skriv inn passordet</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Feil passord</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Ukjent feil</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Innstillinger</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Ingen</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP mellomtjener</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 mellomtjener</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Du har skiftet språk. Start om for å bruke det?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Skjul hovedvinduet ved oppstart</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Gi melding når bibliotekene er synkroniserte</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Aktiver synkronisering av midlertidige filer for MS Office/ LibreOffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Hastighetsbegrensing (KB/s) for nedlasting:</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Hastighetsbegrensning (KB/s) for opplasting: </translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Grunnleggende</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Ikke frakoble synkronisering av et bibliotek automatisk</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Ikke frakoble synkroniseringen av et bibliotek automatisk når dens lokale mappe er fjernet eller utilgjengelig av andre årsaker.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Ikke frakoble synkroniseringen av et bibliotek når det ikke kan gjenfinnes på serveren</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Ikke frakoble synkronseringen av et bibliotek automatisk når det ikke gjenfinnes på serveren</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Slå på FinderSync-utvidelsen</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Slå på Windows utforsker utvidelsen</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Ikke verifiser serversertifikatet med HTTPS-sykronisering</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Avansert</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Språk (krever omstart)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Språk</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Mellomtjenertype:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Vert:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Brukernavn:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Passord:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Mellomtjeneren krever et passord</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Nettverk</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Delingslenke</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Delingslenke:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopier til utklippstavlen</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Ubekreftet tilkobling</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 bruker et et ugyldig sikkerhetssertifikat. Tilkoblingen kan være usikker. Ønsker du å fortsette?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Nåværende RSA-nøkkel fingeravtrykk er %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Tidligere RSA-nøkkel fingeravtrykk er %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Husk valget mitt</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nei</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Åpne</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Åpne denne filen</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>Se på &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>se denne filen på websiden</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>prøv på nytt</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Kunne ikke hente informasjon for favorittmarkerte filer<br/>Vennligst %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Du har ingen favorittmarkerte filer enda.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Avinstallere %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Ønsker du å fjerne %1 kontoinformasjonen?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Fjerner kontoinformasjon...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>tekst</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nei</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl_BE" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>mislukt om de database account te openen</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Account instellingen</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Gelieve het server adres in te vullen</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 is geen geldig server adres</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Mislukt om de account informatie op te slaan</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Mislukt om aanpassingen op te slaan: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Huidige account informatie succesvol geüpdatet</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Server adres</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Mislukt om het synchroniseren van deze account te stoppen: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>klik om de website te openen</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Geen account</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Account instellingen</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Voeg een account toe</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulier</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Account</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>server</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>probeer opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Mislukt om de activiteiten informatie te krijgen. Gelieve%1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Mislukt om de avatars map te maken</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Download taken</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>verwijder alle succesvolle taken</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Momenteel geen download taken.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Wissen</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Bibliotheek</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Pad</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Annuleer deze taak</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>annuleer deze taak</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Verwijder deze taak</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Mislukt om deze taak te annuleren:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Mislukt om deze taak te verwijderen:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimaliseren</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotheken</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favoriet</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Activiteiten</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>huidige downloadsnelheid</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>huidige uploadsnelheid</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Gelieve een te synchroniseren map te kiezen</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>geen server verbonden</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>alle servers verbonden</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>enkele servers zijn niet verbonden</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulier</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimaliseren</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>sluiten</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Selecteer</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>of Plaats Map om te Synchroniseren</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>downloadsnelheid</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>pijlomlaag</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>uploadsnelheid</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>pijlomhoog</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Fout tijdens het aanmaken van ccnet configuratie</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>mislukt om %1 te lezen</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Aanmaken bibliotheek</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Gelieve een map te kiezen</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Aanmaken...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Gelieve de te synchroniseren map te kiezen</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>De map %1 bestaat niet</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Gelieve de naam in te vullen</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Gelieve het paswoord in te vullen</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Paswoorden komen niet overeen</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Mislukt om download taak toe te voegen:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Mislukt om een bibliotheek aan te maken op de server:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Pad:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Kies</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Naam:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>versleuteld</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Paswoord:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Nogmaals Paswoord:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>status tekst</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Gelieve het paswoord in te vullen</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Synchronisatie bibliotheek "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Mislukt om download taak toe te voegen:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Mislukt om de repo download informatie te halen:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Download Bibliotheek</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>kies...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Paswoord voor deze bibliotheek:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Aanpassingen Details</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Cloud Bestand Browser</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Terug</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Verder</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Startpagina</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Bestanden uploaden</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Een map uploaden</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Je hebt geen toelating om bestanden naar deze bibliotheek te uploaden</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Maak een map</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Map naam</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Ongeldige map naam!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>De naam "%1" is reeds in gebruik.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>probeer opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Mislukt om bestand informatie te krijgen<br />Gelieve %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Bestand %1 bestaat reeds.<br/>Wil je dit overschrijven?<br/><small>(Kies Nee om te uploaden onder een andere naam).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Mislukt om bestand te downloaden: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Kies een bestand om te uploaden</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Kies een map om te uploaden</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Hernoemen</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Ben je zeker dat je deze items wilt verwijderen</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Aanmaken map is mislukt</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Kies een bestand om te updaten %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Hernoemen is mislukt</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Verwijderen is mislukt</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Delen is mislukt</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Kan geen bestanden uit dezelfde map plakken</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kopiëren is mislukt</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Verplaatsen is mislukt</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Uploaden</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Uploaden %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Download</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Downloaden %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 van %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Handeling geannuleerd</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>in behandeling</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Interne Server Fout</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Naam</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Grootte</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Laatste Aanpassing</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Hernoem</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Verwijder</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Update</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Kopieer</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>S&nij</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Plak</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Mislukt om mappen te maken</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Mislukt op tijdelijke bestanden te maken</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Mislukt om bestand naar de schijf te schrijven</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Mislukt om de oude versie van het gedownloade bestand te verwijderen</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Mislukt om bestand te verplaatsen</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Initialisatie</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Gelieve een map te kiezen</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Initialisatie is nog niet gedaan. Zeker dat u wil stoppen?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>De map %1 bestaat niet</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Kies...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Volgende</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Controleer je standaard bibliotheek...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Aanmaken standaard bibliotheek...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Mislukt om de standaard bibliotheek aan te maken:
+
+De server versie moet minstens 2.1 of hoger zijn om dit te ondersteunen.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Mislukt om de standaard bibliotheek te halen:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Mislukt om de standaard bibliotheek aan te maken:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Downloaden standaard bibliotheek...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Mislukt om de standaard bibliotheek te downloaden:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>De standaard bibliotheek werd gedownload.
+Je kan op "Open" klikken om het te bekijken.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Fout tijdens het downloaden van de standaard bibliotheek: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Mislukt op de standaard bibliotheek te downloaden:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Overslaan</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Draaien in Achtergrond</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Open</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Klaar</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Download Standaard Bibliotheek</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Voeg een account toe</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Inloggen...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Netwerk Fout:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Waarschuwing:</b> Het ssl certificaat van deze server is niet betrouwbaar, toch doorgaan?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Gelieve het server adres in te vullen</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 is geen geldig server adres</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Gelieve de gebruikersnaam in te vullen</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Vul de computernaam in</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Gelieve het paswoord in te vullen</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Foute email of paswoord</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Te snel ingelogd, wacht een minuutje</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Interne Server Fout</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Mislukt om in te loggen: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Mislukt om in te loggen</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Server:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Bijvoorbeeld: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>of http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Paswoord:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>status tekst</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Computernaam:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>v.b. Jim's laptop</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Login</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Vernieuwen</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>gesynchroniseerd</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexeren bestanden</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>initialisatie synchronisatie</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>bezig met downloaden</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>bezig met uploaden</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>synchronisatie samenvoeging</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>wachten ome te synchroniseren</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>server niet verbonden</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>server authenticatie</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>auto synchronisatie is uitgeschakeld</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>onbekend</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>De opslag quota is opgebruikt</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>initialisatie...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>verbinden met server...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexatie bestanden...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Aanmaken map...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Samenvoegen aanpassingen bestand...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Klaar</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Annulatie</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Geannuleerd</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL Fout</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Netwerk Fout: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Server Fout</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>mislukt om de certs databank te openen</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 kon geen toepassing vinden om het bestand %2 te openen</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Aanmaken bibliotheek "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Bbibliotheek "%1" verwijderd</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Hernoem %1 naar</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Kan item "%1" niet downloaden</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>kopiëren is mislukt</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Toegevoegd</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Verwijderd</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Verwijderd</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Aangepast</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Hernoemd</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Verplaatst</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Map toegevoegd</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Map verwijderd</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Map hernoemd</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Map verplaatst</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>bestanden</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>mappen</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>en %1 meer</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Bibliotheek teruggezet naar status van</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Bestand "%1" teruggezet naar status van %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Terugplaatsen verwijderde map</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Bibliotheek naam of beschrijving aangepast</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Nu</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 dag geleden</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 dagen geleden</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 uur geleden</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 uren geleden</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 minuut geleden</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 minuten geleden</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Geen Deel van Certificaat></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Bbiliotheek "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Deze bibliotheek werd nog niet gedownload</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Fout:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>RepoIcon</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>RepoName</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>TextLabel</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Eigenaar:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Laatst Aangepast:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Grootte:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Lokaal Pad:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Status:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>RepoStatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Naam:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Deze bibliotheek werd niet gedownload</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Recentelijk Aangepast</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Mijn Bibliotheken</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Onderverdeling Bibiliotheken</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Gesynchroniseerde Bibliotheken</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Uitschakelen auto sync</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Inschakelen auto sync</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Toon de details van deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Synchroniseer deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Synchroniseer deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Recentelijk Aangepast</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Synchroniseer deze bibliotheek onmiddellijk</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancel download</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Annulatie download van deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Open map</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>open lokale map</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Unsync</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>annulatie synchronisatie van deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Bekijk in de cloud</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>Bekijk deze bibliotheek op seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Hersynchroniseer deze bibliotheek opnieuw</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>annulatie synchronisatie en hersynchronisatie van deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Mislukt om synchronisatie van bibliotheek "%1" te annuleren</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Mislukt om deze taak te annuleren:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>De download werd geannuleerd</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Kan bestand "%1" niet verwijderen</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Mislukt om bestand te uploaden: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>probeer opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Mislukt om bestand informatie te krijgen<br />Gelieve %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Waarschuwing:</b> Het ssl certificaat van deze server is niet betrouwbaar, toch doorgaan?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Mislukt om de log te initialiseren: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Uitschakelen auto sync</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Inschakelen auto synchronisatie</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Afsluiten</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Toon hoofdvenster</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Instellingen</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>&Log map openen</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Hierover</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Toon de toepassings' Hierover kader</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Online help</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Bestand</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>auto synchronisatie is uitgeschakeld</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Uploaden</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Downloaden</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>enkele servers zijn niet verbonden</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Servers verbindingsstatus</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>verbonden</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>verbinding verbroken</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Geef het bibliotheek paswoord</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Geef het paswoord voor bibliotheek %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Vul het paswoord in</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Onjuist paswoord</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Instellingen</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Je hebt de taal veranderd. Herstarten om dit toe te passen?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Verberg hoofdvenster na start</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Melden wanneer bibliotheken gesynchroniseerd zijn</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Activeren synchronisatie van tijdelijke bestanden MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Download snelheid limiet (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Upload snelheid limiet (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Basis</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Annuleer niet automatisch het synchroniseren van een bibliotheek</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Annuleer niet automatisch het synchroniseren van een bibliotheek als de lokale map verwijderd is of om andere redenen niet toegankelijk is.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Annuleer het synchroniseren van een bibliotheek niet wanneer deze niet gevonden wordt op een server</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Annuleer niet automatisch het synchroniseren van een bibliotheek wanneer deze niet gevondenn wordt op een server</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Controleer het server certificaat in HTTPS synchronisatie niet</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Geavanceerd</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Taal (herstart vereist)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Taal</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Paswoord:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleer</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Deel Link</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Deel link:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopieer naar klembord</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Onvertrouwde Verbinding</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 gebruikt een ongeldig veiligheidscertificaat. De verbinding kan onveilig zijn. Wil je verdergaan?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Huidige RSA sleutel vingerafdruk is %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Vorige RSA sleutel vingerafdruk is %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Onthou mijn keuze</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nee</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Open</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Open dit bestand</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>bekijk op &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>bekijk dit bestand op de website</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>probeer opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Mislukt om informatie van favoriete bestanden te bekijken<br/>Gelieve %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Je hebt nog geen favoriete bestanden.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Desinstalleer %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Wil je de %1 account info verwijderen?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Verwijdering account info...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>tekst</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nee</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="nl_NL" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Over %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Over</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Controleren op updates</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>kon accountdatabase niet openen</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Autorisatie verlopen, graag opnieuw aanmelden</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Accountinstellingen</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Geef serveradres op</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 is geen geldig serveradres</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Kon accountinformatie niet opslaan</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Kon de wijzigingen niet opslaan: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Bijwerken huidige accountinformatie gelukt</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoogvenster</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Serveradres</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-mail</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Kon bibliotheken van dit account niet desynchroniseren: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>klik om de website te openen</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>pro-versie</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Geen account</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Kies</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Accountinstellingen</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Aanmelden</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Verwijderen</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Account toevoegen</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Afmelden</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>niet aangemeld</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulier</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Account</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>e-mail</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>server</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Bestandsactiviteit wordt uitsluitend ondersteund in %1 Server Professional editie.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Ophalen van informatie activiteiten mislukt. %1 a.u.b.</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Upload gelukt</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Bestand "%1"
+succesvol geüpload.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Bestand "%1"
+kon niet worden geüpload.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Machtigingen Fout!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorisatie verlopen</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Bestand bestaat niet</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Upload Fout: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Kon de avatarsmap niet aanmaken</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Machtigingen Controleren</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Taken downloaden</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>verwijder alle succesvolle taken</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Op dit moment geen downloadtaken</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Opschonen</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Bibliotheek</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Pad</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Deze taak annuleren</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>deze taak annuleren</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Deze taak verwijderen</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Kon deze taak niet annuleren:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Kon deze taak niet verwijderen:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimaliseren</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotheken</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Favorieten</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Activiteiten</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Zoeken</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>huidige downloadsnelheid</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>huidige uploadsnelheid</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Kies een map om te synchroniseren</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>geen server verbonden</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>alle servers verbonden</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>sommige servers niet verbonden</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulier</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimaliseren</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>sluiten</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Selecteer</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>of sleep een map om te synchroniseren</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>downloadsnelheid</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>pijlomlaag</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>uploadsnelheid</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>pijlomhoog</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Fout bij het maken van de ccnet-configuratie</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Kon de voorgeconfigureerde map "%1" niet aanmaken</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>kon %1 niet lezen</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Een bibliotheek aanmaken</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Kies een map</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Aanmaken...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Kon geen encryptiesleutel voor deze bibliotheek genereren</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Kies een map om te synchroniseren</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>De map %1 bestaat niet</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Geef de naam op</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Geef het wachtwoord op</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Wachtwoorden komen niet overeen</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Kon geen downloadtaak toevoegen:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Kon geen bibliotheek op de server aanmaken:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Pad:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Kies</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Naam:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>gecodeerd</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Wachtwoord:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Wachtwoord opnieuw:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>statustekst</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>Initialiseren van %1 client mislukt</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 onverwacht afgesloten</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Geef het wachtwoord op</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Synchroniseer bibliotheek "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Synchroniseer map "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Synchroniseer naar map:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>of</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>synchroniseer met een bestaande map</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>een nieuwe synchronisatiemap aanmaken</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Synchroniseer met deze bestaande map:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Kies een map</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>De map bestaat niet</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Kies de map om te synchroniseren.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Je organisatie heeft de mogelijkheid een bibliotheek buiten de map %1 te plaatsen uitgeschakeld.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Conflicteert met bestaande bestand "%1". Kies een andere map.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Conflicteert met bestaande bibliotheek "%1". Kies een andere map.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>De map "%1" bestaat reeds. Weet je zeker dat je hiermee wilt synchroniseren (inhoud zal worden samengevoegd)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Kies nee om in plaats daarvan met een nieuwe map te synchroniseren</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Kan geen alternatieve mapnaam vinden</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Kon geen downloadtaak toevoegen:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Kon de repository download informatie: %1 niet ophalen</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Bibliotheek downloaden</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>kies...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Wachtwoord voor deze bibliotheek:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Wijzigingendetails</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Toegevoegde bestanden</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Verwijderde bestanden</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Gewijzigde bestanden</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Toegevoegde mappen</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Verwijderde mappen</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Open</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Bovenliggende map openen</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Bestandsbeheer cloud</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Terug</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Vooruit</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Begin</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Bestanden uploaden</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Een map uploaden</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Je hebt geen rechten op bestanden naar deze bibliotheek te uploaden</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Een map aanmaken</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Vernieuwen</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Mapnaam</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Ongeldige mapnaam!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>De naam "%1" is al in gebruik.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Kon geen bestandsinformatie ophalen<br/>%1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Deze map is leeg.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Geef de bestandsnaam op...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Kon het bestand "%1" niet verwijderen</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Geef het pad naar de map waarheen je wilt opslaan op...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Wil je het bestaande bestand "%1" overschrijven?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Bestand "%1" is niet gesynchroniseerd</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Bestand %1 bestaat reeds.<br/>Wil je deze overschrijven?<br/><small>(Kies nee om te uploaden met een alternatieve naam)</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Bestand bestaat niet</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Kon bestand niet downloaden: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Kies een te uploaden bestand</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Kies een te uploaden map</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Hernoemen</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Weet je zeker dat je deze items wilt verwijderen?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Aanmaken map mislukt</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Bestandsvergrendeling mislukt</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Kies een bestand om bij te werken %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Hernoeming mislukt</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Verwijderen mislukt</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Delen mislukt</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Kan geen bestanden plakken vanuit dezelfde map</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>Kan de map niet plakken in zijn onderliggende map</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kopiëren mislukt</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Verplaatsen mislukt</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Aanmaken bibliotheek mislukt!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Je hebt geen rechten om naar deze map te uploaden</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorisatie verlopen</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Machtigingen Fout!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Bibliotheek/Map niet gevonden.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Zoek bestanden</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Uploaden</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Uploaden %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Downloaden</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Downloaden %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 van %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Opnieuw</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Overslaan</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Afbreken</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Opslaan</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Bestand opslaan niet gelukt</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Naam</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Grootte</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Laatst aangepast</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Laat zien in map</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Laat zien in map</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Bewerking geannuleerd</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>in behandeling</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>Opdracht afgebroken</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Interne serverfout</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>De opslaglimiet is bereikt</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>vergrendeld door %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Naam</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Grootte</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Laatst gewijzigd</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>Op&slaan als...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Vergrendelen</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Hernoemen</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Verwijderen</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Delen met groep</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Bijwerken</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Kopiëren</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Knippen</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Plakken</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Download &annuleren</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Synchroniseer deze map</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Deze eigenschap is alleen beschikbaar in de pro-versie
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>%1 downloadlink &genereren</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Delen met gebruiker</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>Interne %1link g&enereren</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>Op&slaan als...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>&Ontgrendelen</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Kon alleen-lezen bestanden niet verwijderen</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Kon alleen-lezen bestanden niet knippen</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Opnieuw Uploaden</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Lokale versie verwijderen</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Lokale versie opslaan als...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Kon geen mappen aanmaken</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Kon geen tijdelijke bestanden aanmaken</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Kon bestand niet naar schijf wegschrijven</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Kon oudere versie van het gedownloade bestand niet verwijderen</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Kon bestand niet verplaatsen</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 initialisatie</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Kies %1-map</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Kies een map</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Initialisatie is niet afgerond. Wil je echt afsluiten?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>De map %1 bestaat niet</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Kies een map</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Kies een map. We zullen hierin een submap %1 aanmaken. Wanneer je een bibliotheek download zal deze hier standaard worden opgeslagen.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Kies...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Volgende</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Controleren van je standaardbibliotheek...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Aanmaken van de standaardbibliotheek...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Kon geen standaardbibliotheek aanmaken:
+
+Deze functie wordt alleen ondersteund in serverversie 2.1 of hoger.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Kon de standaardbibliotheek niet ophalen:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Kon de standaardbibliotheek niet aanmaken:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Standaardbibliotheek downloaden...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Kon standaardbibliotheek niet downloaden:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>De standaardbibliotheek is gedownload.
+Je kunt op de knop "Openen" klikken om deze te bekijken.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Fout bij het downloaden van de standaardbibliotheek: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Kon standaardbibliotheek niet downloaden:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Overslaan</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Op de achtergrond uitvoeren</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Open</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Afronden</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Standaardbibliotheek downloaden</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>Meer laden</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Upload log bestanden mislukt</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Upload log bestanden</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Comprimeren</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 van de %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Een account toevoegen</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Opnieuw aanmelden</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Aanmelden...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Netwerkfout:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Waarschuwing:</b> Het SSL-certificaat van deze server is niet vertrouwd. Toch doorgaan?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Geef serveradres op</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 is geen geldig serveradres</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Geef de gebruikersnaam op</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Geef de computernaam op</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 serveradres</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>Server adres kan niet leeg zijn</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 is geen valide server adres. Het moet starten met 'https://'</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Geef het wachtwoord op</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>E-mailadres of wachtwoord onjuist</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Te kort na elkaar aangemeld. Een minuut wachten alstublieft</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Interne serverfout</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Kon niet aanmelden: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Kon niet aanmelden</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Server:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Bijvoorbeeld: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>of http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Wachtwoord:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>statustekst</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Computernaam</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>E-mailadres / Gebruikersnaam:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>bijv. Laptop van Jan</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Aanmelden</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Automatisch Inloggen</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Je bent afgemeld.</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>aanmelden</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Een account toevoegen</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Vernieuwen</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>"%1"is gesynchroniseerd</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Bestanden geupload naar "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Deel %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Geef de groepsnaam op</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Voer gebruikersnaam of email adres in</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Succesvol bijgewerkt</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>Actie om te delen mislukt: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Succesvol verwijderd</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Kon deelinformatie van de map niet ophalen</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Kon je groeps- en contactinformatie niet ophalen</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Geef de gebruikersnaam op</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Geef de groepsnaam op</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Groep "%1" bestaat niet</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Reeds gedeeld met groep %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Reeds gedeeld met gebruiker %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>De vorige opdracht wordt nog uitgevoerd</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoogvenster</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Delen met:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Delen</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Rechten:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Lezen en schrijven</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Alleen lezen</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>gesynchroniseerd</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>bestanden indexeren</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>synchronisatie initialiseren</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>downloaden</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>uploaden</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>Synchronisatie samenvoegen</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>wachten op synchronisatie</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>server niet verbonden</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>serverauthenticatie</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>automatische synchronisatie is uitgeschakeld</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>onbekend</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Netwerkfout</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>Kan het server adres niet vinden</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Kan geen verbinding maken met de server</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Kan geen veilige verbinding opzetten. Controleer het SSL certificaat van de server.</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Serverfout</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Niet genoeg geheugen</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Bibliotheek is op de server verwijderd</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Bibliotheek is beschadigd op de server</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>De opslaglimiet is bereikt</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Initialiseren...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>verbinding maken met server...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>bestanden indexeren...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Bestandslijst downloaden...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Bestanden downloaden...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Map aanmaken...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Bestandswijzigingen samenvoegen...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Klaar</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>serverinfo controleren...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Geannuleerd</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL-fout</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Netwerkfout: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Serverfout</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>kon certificatendatabase niet openen</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Bestand "%1" bestaat niet in "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 kon geen applicatie vonden op het bestand %2 te openen</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Bibliotheek "%1" aangemaakt</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Bibliotheek "%1" verwijderd</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>%1 hernoemen naar</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Kon item "%1" niet downloaden</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>kopie mislukt</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Toegevoegd</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Verwijderd</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Verwijderd</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Gewijzigd</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Hernoemd</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Toegevoegd of gewijzigd</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Verplaatst</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Map toegevoegd</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Map verwijderd</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Map hernoemd</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Map verplaatst</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>bestanden</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>mappen</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>en nog %1 andere</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Bibliotheek teruggezet naar de status van</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Bestand "%1" teruggezet naar de status van %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Verwijderde map hersteld</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Naam of beschrijving van de bibliotheek gewijzigd</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Automatisch samenvoegen door het %1systeem</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Zojuist</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 dag geleden</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 dagen geleden</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 uur geleden</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 uur geleden</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 minuut geleden</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 minuten geleden</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Geen onderdeel van certificaat></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Synchroniseer deze bibliotheek naar:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Synchroniseer deze map naar:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Map</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Alleen-lezen map</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Document</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF-document</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Afbeeldingsbestand</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Tekstdocument</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Audiobestand</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Videobestand</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Worddocument</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint-document</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Exceldocument</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Het pad "%1" conflicteert met het systeempad</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Het pad "%1" conflicteert met een bestaande bibliotheek</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>uploaden van de bestandslijst</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Pad is ongeldig</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Fout bij indexeren</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>Bestand bestaat niet</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Bibliotheek "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Deze bibliotheek is nog niet gedownload</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Fout:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>elke %1 seconden</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Bibliotheeksymbool</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Bibliotheeknaam</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Tekstlabel</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Eigenaar:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Laatst gewijzigd:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Grootte:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Lokaal pad:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Status:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Bibliotheekstatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Naam:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Synchronisatie-interval:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Deze bibliotheek is niet gedownload</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Kon het bestand "%1" van de niet-bestaande bibliotheek "%2" niet openen</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Onlangs bijgewerkt</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Mijn bibliotheken</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Subbibliotheken</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Gedeeld met mij</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Gedeeld met iedereen</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Gedeeld met groepen</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Gesynchroniseerde bibliotheken</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>Synchronisatie initialiseren</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Automatische synchronisatie uitschakelen</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Automatische synchronisatie inschakelen</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>&Details weergeven</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Details van deze bibliotheek weergeven</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Synchroniseer deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Synchroniseer deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Onlangs bijgewerkt</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>&Nu synchroniseren</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Synchroniseer deze bibliotheek meteen</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>Download &annuleren</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Download van deze bibliotheek annuleren</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>Map &openen</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>lokale map openen</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>Lokale map &openen</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Desynchroniseren</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>desynchroniseer deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>In cloud weergeven</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>Geef deze bibliotheek in de cloud weer</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Delen met gebruiker</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Deel deze bibliotheek met een gebruiker</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Delen met groep</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Deel deze bibliotheek met een groep</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Open bestandsbeheer cloud</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>Open deze bibliotheek in de ingebouwde cloud-bestandsbeheerder</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Hersynchroniseer deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>de- en hersynchroniseer deze bibliotheek</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Synchronisatie-interval instellen</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Kon de bibliotheek "%1" niet desynchroniseren</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Kon deze taak niet annuleren:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>De download is geannuleerd</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Kon het bestand "%1" niet met zichzelf overschrijven</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Kon het bestand "%1" niet verwijderen</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Kon bestand niet uploaden: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Synchronisatie-interval (in seconden):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Synchronisatieinterval voor bibliotheek "%1" instellen</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Bibliotheken zoeken</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Kon geen informatie over bibliotheken ophalen<br/>%1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Waarschuwing</b> Het SSL-certificaat van deze server is niet vertrouwd. Toch doorgaan?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Kon logbestand niet initialiseren: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nee</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>Interne %1-link</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopiëren naar klembord</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Automatische synchronisatie uitschakelen</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Automatische synchronisatie inschakelen</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Afsluiten</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Toon applicatiescherm</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Instellingen</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>&Map %1 openen</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>Map %1 openen</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Map &logboeken openen</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Synchronisatie fouten laten zien.</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Over</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Toon het scherm met informatie over de applicatie</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Online help</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Bestand</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>automatische synchronisatie is uitgeschakeld</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Uploaden</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Downloaden</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>map %1 logboeken openen</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>open %1 online hulp</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>sommige servers niet verbonden</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Upload log bestanden</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>upload %1 log bestanden</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Eerst inloggen A.U.B.</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>In map &tonen</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>In map tonen</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Bestanden zoeken</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Kon niet zoeken<br/>
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Verbindingsstatus servers</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>verbonden</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>niet verbonden</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Sluiten</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Geef het bibliotheekwachtwoord op</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Geef het wachtwoord voor de bibliotheek %1 op</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Geef het wachtwoord op</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Wachtwoord onjuist</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Onbekende fout</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Instellingen</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>%1 automatisch opstarten na het aanmelden</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>%1-icoon verbergen</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Geen</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP-proxy</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5-proxy</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Systeem proxy</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Je hebt de taal gewijzigd. Herstarten op de wijziging door te voeren?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>Het proxy server adres kan niet leeg zijn</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>De proxy netwerkpoort is onjuist</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>De proxy gebruikersnaam mag niet leeg zijn</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>Het proxy wachtwoord mag niet leeg zijn</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Applicatiescherm verbergen na opstarten</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Melding wanneer bibliotheken zijn gesynchroniseerd</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Synchronisatie tijdelijke bestanden van MSOffice/Libreoffice inschakelen</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Snelheidslimiet download (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Snelheidslimiet upload (KB/s)</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Basis</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Bibliotheek niet automatisch desynchroniseren</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Bibliotheek niet automatisch desynchroniseren wanneer de lokale map is verwijderd of niet toegankelijk is om andere redenen.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Niet desynchroniseren wanneer niet op de server gevonden</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Bibliotheek niet automatisch desynchroniseren wanneer deze niet op de server kan worden gevonden</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>FinderSync-extensie inschakelen</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Verkenner-extensie inschakelen</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Automatisch op updates controleren</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Het servercertificaat bij HTTPS-synchronisatie niet verifiëren</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Synchroniseren met een bestaande map met een andere naam inschakelen</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Geavanceerd</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Taal (herstart noodzakelijk)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Taal</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Proxytype:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Host:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Poort:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Gebruikersnaam:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Wachtwoord:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Proxyserver vereist een wachtwoord</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Netwerk</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Lezen en schrijven</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Alleen lezen</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Verwijder gedeelde onderdeel</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Klik om aan te passen</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Aangemaakt door %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Lezen en schrijven</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Alleen lezen</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Groep</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Gebruiker</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Rechten</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>De vorige opdracht wordt nog uitgevoerd</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Deellink</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Deellink:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Directe download</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopiëren naar klembord</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Niet-vertrouwde verbinding</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 gebruikt een ongeldig beveiligingscertificaat. De verbinding kan onveilig zijn. Wil je toch doorgaan?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Huidige RSA-vingerafdruk is %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Voorgaande RSA-vingerafdruk is %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Mijn keuze onthouden</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nee</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Open</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Open dit bestand</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>op web weergeven</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>bekijk dit bestand op de website</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>opnieuw</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Kon geen informatie over favorieten ophalen<br/>%1 a.u.b.</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Je hebt nog geen favoriete bestanden.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Bestands synchronisatie fouten</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Geen synchronisatie fouten.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Dubbel klik om de bibliotheek te openen.</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Bibliotheek</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Pad</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Fout</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Tijd</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Dit apparaat onthouden</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Annuleren</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Ok</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Deïnstalleer %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Wil je de accountinformatie van %1 verwijderen?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Accountinformatie verwijderen...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialoog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>tekst</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nee</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pl_PL" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>O %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Klient %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> Rew. %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>O programie</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Sprawdź aktualizacje</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>nie udało się otworzyć bazy danych konta</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Autoryzacja wygasła, proszę zalogować się ponownie</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Nie udało się usunąć tokena synchronizacji lokalnego repozytorium: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Nie udało się pobrać informacji synchronizacji z serwera: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Ustawienia konta</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Proszę podać adres serwera</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 nie jest poprawnym adresem serwera</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Nie udało się zapisać informacji o koncie</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Nie udało się zapisać zmian: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Pomyślnie zaktualizowano dane obecnego konta</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Adres serwera</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-mail</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>Czy na pewno chcesz usunąć konto %1?<br><br>Konto zostanie usunięte tylko lokalne wraz ze wszystkimi ustawieniami synchronizacji. Konto na serwerze pozostanie nietknięte.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Nie udało się odsynchronizować bibliotek konta: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>kliknij, aby otworzyć witrynę</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>wersja pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Brak konta</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Wybierz</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Ustawienia konta</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Zaloguj</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Usuń</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Dodaj konto</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Wyloguj</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>niezalogowany</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formularz</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Konto</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>adres e-mail</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>serwer</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Aktywności pliku są obsługiwane wyłącznie przez %1 Server Professional Edition.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>ponów</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Nie udało się uzyskać informacji o aktywnościach. Proszę %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Przesyłanie zakończone powodzeniem</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Plik "%1"
+przesyłanie udane.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Plik "%1"
+nieudane przesyłanie.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Brak dostępu!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autoryzacja wygasła</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Plik nie istnieje</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>Plik jest zablokowany przez %1, proszę spróbować później</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Niepowodzenie wgrywania: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Nie udało się utworzyć katalogu awatarów</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Sprawdzanie uprawnień</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Zadania pobierania</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>usuń wszystkie zakończone zadania</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Brak zadań pobierania.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Wyczyść</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zamknij</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteka</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ścieżka</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Anuluj to zadanie</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>anuluj to zadanie</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Usuń to zadanie</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Nie udało się anulować tego zadania:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Nie udało się usunąć tego zadania:
+
+ %1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimalizuj</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zamknij</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Biblioteki</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Ulubione</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Aktywności</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Szukaj</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>aktualna prędkość pobierania</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>aktualna prędkość wysyłania</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Wybierz folder do synchronizacji</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>brak połączenia z serwerem</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>wszystkie serwery są podłączone</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>niektóre serwery nie zostały podłączone</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formularz</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimalizuj</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>zamknij</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Wybierz</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>lub upuść folder, aby zsynchronizować</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>prędkość pobierania</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>strzałka w dół</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>prędkość wysyłania</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>strzałka w górę</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Błąd podczas tworzenia konfiguracji ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Nie można utworzyć wstępnie skonfigurowanego folderu "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>nie udało się odczytać %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Utwórz bibliotekę</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Proszę wybrać folder</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Tworzenie...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Nie udało się wygenerować klucza szyfrowania dla tej biblioteki</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Proszę wybrać folder do synchronizacji</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Folder %1 nie istnieje</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Proszę podać nazwę</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Proszę podać hasło</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Hasła się nie zgadzają</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nieznany błąd</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Nie udało się dodać zadania pobierania:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Nie udało się utworzyć biblioteki na serwerze:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Ścieżka:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Wybierz</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nazwa:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>zaszyfrowana</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Hasło:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Powtórz hasło:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>tekst statusu</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>nie można zainicjować klienta %1</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 zakończył się niespodziewanie</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Proszę podać hasło</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Synchronizuj bibliotekę "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Synchronizuj folder "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Synchronizuj do folderu:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>lub</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>synchronizuj z istniejącym folderem</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>utwórz nowy folder synchronizacji</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Synchronizuj z tym istniejącym folderem:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Proszę wybrać folder</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Folder nie istnieje</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Proszę wybrać folder do synchronizacji.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Twoja organizacja nie pozwala na umieszczanie biblioteki poza folderem %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Konflikt z istniejącym plikiem "%1", proszę wybrać inny folder.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Konflikt z istniejącą biblioteką "%1", proszę wybrać inny folder.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Folder "%1" już istnieje. Na pewno chcesz z nim synchronizować (zawartość zostanie połączona)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Kliknij Nie, aby synchronizować z nowym folderem</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Nie można odnaleźć alternatywnej nazwy folderu</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Nie udało się dodać zadania pobierania:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Nie udało się uzyskać informacji o pobieraniu repozytorium:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Pobierz bibliotekę</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>wybierz...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Hasło do tej biblioteki:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Szczegóły zmian</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Dodane pliki</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Usunięte pliki</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Zmienione pliki</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Dodane foldery</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Usunięte foldery</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Otwórz</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Otwórz folder nadrzędny</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Przeglądarka plików w chmurze</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Wstecz</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Naprzód</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Strona główna</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Wyślij pliki</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Wyślij folder</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Nie masz uprawnień do przesyłania plików do tej biblioteki</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Utwórz folder</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Odśwież</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 elementów</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Nazwa folderu</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Nieprawidłowa nazwa folderu!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Nazwa "%1" jest już zajęta.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>ponów</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Nie udało się pobrać informacji o plikach<br />Proszę %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Ten folder jest pusty</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Podaj nazwę pliku do zapisania...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Nie można usunąć pliku "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Podaj ścieżkę do folderu, do którego chcesz zapisać...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Czy chcesz nadpisać istniejący plik "%1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Plik "%1" nie został zsynchronizowany</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Plik %1 już istnieje.<br/>Chcesz go nadpisać?<br/><small>(Wybierz Nie, aby zapisać go pod inną nazwą).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Plik nie istnieje</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Nie udało się pobrać pliku: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Wybierz plik do przesłania</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Wybierz folder do wysłania</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Zmień nazwę</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Czy na pewno chcesz usunąć te elementy</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Tworzenie folderu nie powiodło się</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Nie udało się zablokować pliku</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Wybierz plik do aktualizacji %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Nie udało się zmienić nazwy</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Nie udało się usunąć</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Nie udało się udostępnić</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Nie można wklejać plików z tego samego folderu</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>Nie można skopiować folderu do jego podfolderu</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kopiowanie nieudane</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Przenoszenie nieudane</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Nie udało się utworzyć biblioteki!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Nie posiadasz uprawnień do wgrywania do tego folderu</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autoryzacja wygasła</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Brak dostępu!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Nie znaleziono biblioteki/folderu</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Nie udało się wgrać pliku %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>Nie można utworzyć folderu pamięci podręcznej</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>Nie można otworzyć folderu pamięci podręcznej</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Szukaj plików</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Nie udało się pobrać łącza</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>Oczekiwanie</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Wyślij</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Wysyłanie %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Pobierz</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Pobieranie %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 z %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Nie udało się wgrać pliku "%1", czy chcesz spróbować ponownie?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Ponów</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Pomiń</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Przerwij</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Zapisywanie</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Nie udało się zapisać pliku</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Nazwa</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Rozmiar</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Ostatnia modyfikacja</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>Pokaż w folderze</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Pokaż w folderze</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operacja anulowana</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>oczekiwanie</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>anulowano zadanie</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Wewnętrzny błąd serwera</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Dostępna przestrzeń dyskowa została wykorzystana</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>zablokowany przez %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nazwa</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Rozmiar</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Ostatnia zmiana</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>Modyfikujący</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>Zapi&sz jako...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>Zab&lokuj</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>Zmień nazwę</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>Usuń</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Udostępnij grupie</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>Akt&ualizuj</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Kopiuj</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Wy&tnij</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Wklej</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Anuluj pobi&eranie</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Synchronizuj ten folder</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Ta funkcja jest dostępna wyłącznie w wersji pro
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>Wy&generuj łącze pobierania %1</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Udostępnij użytkownikowi</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>Wyg&eneruj %1 wewnętrzne łącze</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>Zapi&sz jako do...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Odb&lokuj</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Nie można usunąć plików tylko do odczytu</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Nie można uciąć plików tylko do odczytu</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Ponów wysyłanie</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Usuń wersję lokalną</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Zapisz lokalną wersję jako...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Otwórz lokalny folder pamięci podręcznej</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Nie udało się utworzyć folderów</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Nie udało się utworzyć plików tymczasowych</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Nie udało się zapisać pliku na dysku</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Nie udało się usunąć starszej wersji pobranego pliku</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Nie udało się przenieść pliku</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>Inicjowanie %1</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Wybierz %1 folder</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Proszę wybrać folder</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inicjowanie nie zostało zakończone: Na pewno wyjść?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Folder %1 nie istnieje</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Wybierz folder</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Proszę wybrać folder wewnątrz którego zostanie utworzony podfolder %1. Gdy pobierzesz bibliotekę, zostanie ona tam domyślnie zapisana.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Wybierz...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Następny</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organizuje pliki w biblioteki.
+Czy chcesz pobrać swoją domyślną bibliotekę?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Sprawdzanie Twojej biblioteki domyślnej...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Tworzenie biblioteki domyślnej...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Nie udało się utworzyć biblioteki domyślnej:
+
+Wymagany serwer w wersji 2.1 lub nowszy.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Nie udało się pobrać biblioteki domyślnej:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Nie udało się utworzyć biblioteki domyślnej:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Pobieranie biblioteki domyślnej...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Nie udało się pobrać biblioteki domyślnej:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Biblioteka domyślna została pobrana.
+Kliknij przycisk "Otwórz", aby ją wyświetlić.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Błąd podczas pobierania biblioteki domyślnej: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Nie udało się pobrać biblioteki domyślnej:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 organizuje pliki w biblioteki.
+Czy chcesz pobrać swoją domyślną bibliotekę?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Pomiń</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Uruchom w tle</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Otwórz</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Zakończ</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Pobierz bibliotekę domyślną</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Tak</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>wczytaj więcej</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Nie udało się wysłać logów</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Wyślij logi</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Brak dostępu!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Nie znaleziono biblioteki/folderu</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autoryzacja wygasła</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Nie udało się wysłać logów: %1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Pomyślnie wysłano logi</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Kompresowanie</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 z %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Dodaj konto</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Pojedyncze logowanie</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Zaloguj ponownie</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Logowanie...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Błąd sieci:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Ostrzeżenie:</b> Certyfikat SSL tego serwera nie jest zaufany, kontynuować?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Podaj adres serwera</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 nie jest prawidłowym adresem serwera</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Proszę podać nazwę użytkownika</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Podaj nazwę komputera</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>Adres serwera %1</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>Adres serwera nie może być pusty</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 nie jest prawidłowym adresem serwera. Adres musi się zaczynać od 'https://'</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Proszę podać hasło</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Nieprawidłowy adres e-mail lub hasło</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Zbyt częste próby logowania, proszę chwilę odczekać</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Wewnętrzny błąd serwera</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Niepowodzenie logowania: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Niepowodzenie logowania</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Serwer:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Na przykład: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>lub http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Hasło:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>tekst statusu</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Nazwa komputera:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Nazwa użytkownika:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>np. laptop Kuby</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Zaloguj</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Logowanie automatyczne</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Jesteś wylogowany. Proszę</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>zaloguj</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Dodaj konto</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Odśwież</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>"%1" jest zsynchronizowana</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Pliki przesłane do "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>Nie udało się zsynchronizować pliku %1
+Plik jest zablokowany przez inną aplikację, będzie przesłany, gdy zostanie ona zamknięta.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>Nie udało się zsynchronizować folderu %1
+Jeden z plików wewnątrz tego folderu jest zablokowany przez inną aplikację. Folder zostanie zaktualizowany, gdy ją zamkniesz.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>Nie udało się zsynchronizować pliku %1
+Plik jest zablokowany przez innego użytkownika. Zmiany w tym pliku nie są synchronizowane.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>Nie udało się zindeksować pliku %1
+Proszę sprawdzić uprawnienia do pliku i dostępną przestrzeń dyskową.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>Nie udało się zsynchronizować %1
+Ścieżka pliku jest zakończona spacją lub kropką i nie może być utworzona w systemie Windows</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>Nie udało się zsynchronizować %1
+Ścieżka do pliku zawiera nieprawidłowe znaki. Plik nie jest synchronizowany z tym komputerem.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>Aktualizacja pliku %1 jest niemożliwa z powodu aktualnej konfiguracji praw dostępu do katalogu.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Udostępnij %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Podaj nazwę grupy</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Podaj nazwę użytkownika lub adres email</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Pomyślnie zaktualizowano</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>Niepowodzenie udostępniania: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Pomyślnie usunięto</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Nie udało się uzyskać informacji udostępniania folderu</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Nie udało się uzyskać informacji o grupach i kontaktach</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Proszę podać nazwę użytkownika</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Proszę podać nazwę grupy</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Grupa "%1" nie istnieje</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Już udostępniono grupie %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Już udostępniono użytkownikowi %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Poprzednia operacja ciągle trwa</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Udostępnij dla:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Udostępnij</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Uprawnienia:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Odczyt-Zapis</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Tylko-odczyt</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zamknij</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>zsynchronizowano</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indeksowanie plików</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicjowanie synchronizacji</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>pobieranie</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>wysyłanie</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>scalanie synchronizacji</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>oczekiwanie na synchronizację</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>serwer nie podłączony</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>uwierzytelnianie serwera</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>synchronizacja automatyczna jest wyłączona</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>nieznany</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nieznany błąd</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Błąd sieci</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>Nie można ustalić adresu serwera proxy</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>Nie można ustalić adresu serwera</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Nie można połączyć się z serwerem</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Nie udało się nawiązać bezpiecznego połączenia. Proszę sprawdzić certyfikat SSL serwera.</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>Transfer został przerwany. Proszę sprawdzić połączenie z siecią lub zaporę</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Przekroczony czas transferu. Proszę sprawdzić połączenie z siecią lub firewall</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Nieobsługiwane przekierowanie http z serwera. Proszę sprawdzić konfigurację serwera.</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Błąd serwera</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Brak pamięci</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>Nie udało się zapisać danych po stronie klienta. Proszę sprawdzić ilość dostępnego miejsca lub uprawnienia do folderu</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Wolne miejsce zostało wykorzystane</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Biblioteka została usunięta z serwera</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Biblioteka na serwerze jest uszkodzona</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Dostępne miejsce zostało wykorzystane</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicjowanie...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>łączenie z serwerem...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indeksowanie plików...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Pobieranie listy plików...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Pobieranie plików...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Tworzenie folderu...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Scal zmiany pliku</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Zakończone</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>sprawdzanie informacji serwera...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Anulowanie</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Anulowano</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Błąd SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Błąd sieci: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Błąd serwera</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>nie udało się otworzyć bazy certyfikatów</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Plik "%1" nie istnieje w "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 nie może odnaleźć aplikacji do otwarcia pliku %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Utworzona biblioteka "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Usunięta biblioteka "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Zmień nazwę %1 na</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Nie można pobrać elementu "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>nie udało się skopiować</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Dodano</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Usunięto</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Usunięto</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Zmieniono</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Zmieniono nazwę</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Dodane lub zmienione</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Przeniesiono</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Dodano folder</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Usunięto folder</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Zmieniono nazwę folderu</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Przeniesiono folder</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>pliki</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>foldery</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>i %1 więcej</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Przywrócono bibliotekę do stanu z</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Przywrócono plik "%1" do stanu z %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Odzyskano usunięty folder</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Zmieniono nazwę lub opis biblioteki</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Automatyczne scalanie przez %1 system</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>przed chwilą</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>wczoraj</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 dni temu</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>godzinę temu</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 godzin temu</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>minutę temu</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 minut temu</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Nie jest częścią certyfikatu></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Synchronizuj tę bibliotekę z:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Synchronizuj ten folder z:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Folder</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Folder tylko do odczytu</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Dokument</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Dokument PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Plik graficzny</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Plik tekstowy</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Plik audio</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Plik wideo</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Dokument Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Dokument PowerPoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Dokument Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Ścieżka "%1" jest w konflikcie ze ścieżką systemową</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Ścieżka "%1" jest w konflikcie z istniejącą biblioteką</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>przesyłanie listy plików</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>Plik jest zablokowany przez inną aplikację</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>Folder jest zablokowany przez inną aplikację </translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>Plik jest zablokowany przez innego użytkownika</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Ścieżka jest nieprawidłowa</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Błąd podczas indeksowania</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>Ścieżka jest zakończona spacją lub kropką</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>Ścieżka zawiera nieprawidłowe znaki, np. "|" lub ":"</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>nie udało się otworzyć podręcznej bazy plików</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>Nazwa biblioteki zawiera nieprawidłowe znaki, takie jak ':', '*', '|', '?'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>Aktualizacja pliku jest niemożliwa z powodu aktualnej konfiguracji praw dostępu do katalogu</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>%1 Client jest już uruchomiony</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>Brak uprawnień do synchronizacji tego folderu</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>Plik nie istnieje</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Biblioteka "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Ta biblioteka nie została jeszcze pobrana</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Błąd:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>co %1 sekund</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Ikona repozytorium</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Nazwa repozytorium</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Etykieta tekstowa</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Właściciel:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Ostatnia zmiana:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Rozmiar:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Ścieżka lokalna:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Status:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Status repozytorium</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nazwa:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Interwał synchronizacji:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zamknij</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Ta biblioteka nie została pobrana</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Nie można otworzyć pliku "%1" z nieistniejącej biblioteki "%2"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Ostatnio aktualizowane</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Moje biblioteki</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Biblioteki podrzędne</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Udostępnione mnie</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Udostępnione wszystkim</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Udostępnione grupom</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Zsynchronizowane biblioteki</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicjowanie synchronizacji</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Wyłącz auto synchronizację</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Włącz auto synchronizację</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Pokaż &szczegóły</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Pokaż szczegóły tej biblioteki</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Synchronizuj tę bibliotekę</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Synchronizuj tę bibliotekę</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Ostatnio zaktualizowane</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Sy&nchronizuj teraz</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Niezwłocznie synchronizuj tę bibliotekę</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>Anuluj pobieranie (&C)</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Anuluj pobieranie tej biblioteki</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Otwórz folder</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>otwórz folder lokalny</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>&Otwórz folder lokalny</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>Wyłącz synchronizację (&U)</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>wyłącz synchronizację tej biblioteki</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>Pokaż w chmurze (&V)</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>pokaż tę bibliotekę w seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Udostępnij użytkownikowi</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Udostępnij tę bibliotekę użytkownikowi</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Udostępnij grupie</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Udostępnij tę bibliotekę grupie</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Otwórz przeglądarkę plików w chmurze</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>otwórz tę bibliotekę we wbudowanej przeglądarce plików w chmurze</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>Opuść udzia&ł</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>opuść udział</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>Synch&ronizuj tę bibliotekę ponownie</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>przestań synchronizować, a następnie ponownie zsynchronizuj tę bibliotekę</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Ustaw &interwał synchronizacji</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>ustaw interwał synchronizacji dla tej biblioteki</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>Czy na pewno chcesz przestać synchronizować bibliotekę"%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>Czy na pewno chcesz ponowić synchronizację biblioteki "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>Czy na pewno chcesz nadpisać plik "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Nie udało się wyłączyć synchronizacji biblioteki "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>Czy na pewno chcesz opuścić udział "%1"?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Nie udało się opuścić udziału</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Nie udało się anulować tego zadania:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Pobieranie zostało anulowane</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>Nie masz uprawnień do przesyłania plików do tego folderu</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Nie można nadpisać pliku "%1" nim samym</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Nie można usunąć pliku "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Nie udało się wgrać pliku: "%1"</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Interwał synchronizacji (w sekundach):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Ustaw interwał synchronizacji dla biblioteki "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Przeszukaj biblioteki</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>ponów</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Nie udało się uzyskać informacji o bibliotekach<br/>Proszę %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Ostrzeżenie:</b> Certyfikat SSL tego serwera nie jest zaufany, kontynuować?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Nie udało się zainicjować logu: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Tak</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nie</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>nie udało się zapisać id klienta</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>nie udało się uzyskać dostępu do %1</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>nieprawidłowe id klienta</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>nie udało się odczytać %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>Łącze wewnętrzne %1</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopiuj do schowka</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>Łącze wewnętrzne %1:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nieznany błąd</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>błąd wewnętrzny: nie udało się połączeń z demonem</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Wyłącz auto synchronizację</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Włącz auto synchronizację</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>Wyjdź (&Q)</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Pokaż główne okno</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Ustawienia</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Otwórz &folder %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>otwórz folder %1</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Otwórz folder z &logami</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Pokaż błędy synchronizacji pliku</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>O progr&amie</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Pokaż okno "O programie"</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>Pomoc &online</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Plik</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>synchronizacja automatyczna jest wyłączona</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Wysyłanie</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Pobieranie</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>otwórz folder z logami %1</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>otwórz pomoc online %1</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>niektóre serwery nie zostały podłączone</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Wyślij pliki logów</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>wyślij %1 logów</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Proszę najpierw się zalogować</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>Pokaż w folderze</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Pokaż w folderze</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Szukaj plików</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>ponów</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Nie udało się wyszukać<br/>Proszę %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Status połączeń serwerów</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>połączono</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>rozłączono</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zamknij</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Proszę podać hasło do biblioteki</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Proszę podać hasło do biblioteki %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Proszę podać hasło</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Nieprawidłowe hasło</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Nieznany błąd</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Ustawienia</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Automatycznie uruchom %1 po zalogowaniu</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Ukryj ikonę %1 w doku</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Brak</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>Proxy HTTP</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Proxy Socks5</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Systemowy serwer pośredniczący</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Zmieniono język. Zrestartować aplikację, aby wprowadzić zmiany?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>Adres serwera pośredniczącego nie może być pusty</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Port serwera pośredniczącego jest nieprawidłowy</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>Nazwa użytkownika serwera pośredniczącego nie może być pusta</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>Hasło serwera pośredniczącego nie może być puste</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Ukryj główne okno podczas uruchamiania</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Powiadom, gdy biblioteki są zsynchronizowane</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Synchronizuj pliki tymczasowe MSOffice/LibreOffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Ogranicz prędkość pobierania (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Ogranicz prędkość wysyłania (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Podstawowe</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Nie wyłączaj automatycznie synchronizacji bibliotek</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Nie wyłączaj automatycznie synchronizacji biblioteki, gdy jej folder lokalny zostanie usunięty lub z innych przyczyn stanie się nieosiągalny.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Nie wyłączaj synchronizacji brakującej na serwerze biblioteki</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Nie wyłączaj automatycznie synchronizacji biblioteki, gdy ta nie zostanie znaleziona na serwerze</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Włącz rozszerzenie FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Włącz rozszerzenie Explorera</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Sprawdzaj aktualizacje automatycznie</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Nie weryfikuj certyfikatu serwera podczas synchronizacji przez HTTPS</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Włącz synchronizację z istniejącym folderem o innej nazwie</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Zaawansowane</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Język (wymaga restartu)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Język</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Rodzaj proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Host:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Nazwa użytkownika:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Hasło:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Serwer proxy wymaga hasła</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Sieć</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Odczyt i zapis</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Tylko odczyt</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Usuń udział</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Kliknij, aby edytować</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Utworzony przez %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Odczyt i zapis</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Tylko odczyt</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Grupa</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Użytkownik</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Uprawnienia</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Poprzednia operacja ciągle trwa</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Łącze udostępniania</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Łącze udostępniania:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Pobieranie bezpośrednie</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Kopiuj do schowka</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Niezaufane połączenie</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 używa nieprawidłowego certyfikatu. Połączenie może nie być bezpieczne. Czy chcesz kontynuować?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Obecny odcisk palca klucza RSA to %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Poprzedni odcisk palca klucza RSA to %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Zapamiętaj mój wybór</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Tak</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nie</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Otwórz</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Otwórz ten plik</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>&wyświetl w sieci</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>wyświetl ten plik w przeglądarce</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>ponów</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Nie udało się uzyskać informacji o ulubionych plikach<br/>Proszę %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Nie masz ulubionych plików.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Błędy Synchronizacji Pliku</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Brak błędów synchronizacji.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Kliknij dwukrotnie, aby otworzyć bibliotekę</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteka</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Ścieżka</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Błąd</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Czas</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Wpisz token uwierzytelniania dwuskładnikowego</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Uwierzytelnianie dwuskładnikowe</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Proszę wpisać token uwierzytelniania dwuskładnikowego</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Zapamiętaj to urządzenie</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Anuluj</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Odinstaluj %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Czy chcesz usunąć informacje o koncie %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Usuwanie informacji o koncie...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>tekst</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Tak</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nie</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_BR" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>Sobre %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Cliente %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>Sobre</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Verificar Atualizações</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>falha ao abrir o banco de dados de contas</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>A autorização expirou. Por favor, faça o autentique-se novamente.</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Falha ao remover repositório local token de sincronização: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Configurações da Conta</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Por favor, informe o endereço do servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 não é um endereço válido de servidor</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Falhou ao salvar as informações da conta</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Falou ao salvar as modificações: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Atualização com sucesso das informações da conta atual</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Endereço do Servidor</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Falhou ao dessincronizar as bibliotecas desta conta: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>clique para abrir o site</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>Versão Pro</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Sem conta</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Escolha</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Configurações da conta</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Login</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Apagar</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Incluir uma conta</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Sair</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>Não conectado</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>De</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Conta</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>servidor</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Atividades de Arquivo são somente suportadas no %1 Servidor Edisão Profissional.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>tentar novamente</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Falhou ao obter informações de atividades. Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Envio de arquivo com sucesso</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Arquivo "%1"
+enviado com sucesso.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Arquivo "%1"
+falhou ao enviar.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Erro de Permissão!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Autorização expirada</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Arquivo nãoexiste</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>O arquivo está bloquado por %1, favor tente mais tarde</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Falha no Upload: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Falhou ao criar pasta de avatares</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Verificando Permissão</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Tarefas de download</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>todas as tarefas removidas com sucesso</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Sem tarefas de download no momento</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Limpar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Caminho</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Cancelar esta tarefa</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>cancela esta tarefa</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Remover esta tarefa</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Falha ao cancelar esta tarefa:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Falha ao remover esta tarefa:
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimizar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechar</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Estrelado</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Atividades</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Procurar</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>taxa atual de download</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>taxa atual de upload</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Favor escolher uma pasta para sincronizar</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>sem servidor conectado</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>todos os servidores conectados</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>alguns servidores não estão conectados</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimizar</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>fechar</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Selecionar</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>marca</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>ou Solte a Pasta aqui para Sincronizar</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>taxa de download</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>downarrow</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>taxa de upload</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>uparrow</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Erro ao criar a configuração ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Não foi possivel criar um diretorio pré-configurado "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>falla ao ler %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Criar uma biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Por favor escolha uma pasta</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Criando...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Falha ao gerar chave de encriptação para essa biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Por favor escolha uma pasta para sincronizar</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>A pasta %1 não existe</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Por favor informe o nome</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Por favor informe a senha</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>As senhas não batem</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erro deconhecido</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Falha ao incluir a tarefa de download:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Falhou ao criar biblioteca no servidor:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Caminho:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Escolher</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nome:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>encriptado</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Senha:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Senha de novo:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>texto de status</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 cliente falhou ao inicializar</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 saiu inesperadamente</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Por favor informe a senha</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Sincronizar pasta "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Sincronizar para a pasta:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ou</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>sincronizar com uma pasta existente</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>criar uma nova pasta de sincronização</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Sincronizar com uma pasta existente:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Por favor, escolha uma pasta</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>A pasta não existe</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Por favor, escolha a pasta para sincronizar.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Sua organização desabilitou colocando uma biblioteca fora da 1% pasta.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Conflito com um arquivo existente "%1". Por favor, escolha uma pasta diferente.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Conflito com uma biblioteca existente "%1". Por favor, escolha uma pasta diferente.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>A pasta "% 1" já existe. Tem certeza que deseja sincronizar com ele ( os conteúdo serão mesclados ) ?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Clique em Não para sincronizar com a nova pasta.</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>
+Incapaz de encontrar um nome alternativo para a pasta</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Falha ao incluir a tarefa de baixar:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Falha ao obter informação de descarga do repositório:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Biblioteca de download</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>escolher...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Senha para esta biblioteca:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Detalhes da Modificação</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Arquivos Adicionados</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Arquivos Apagados</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Arquivos Modificados</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Pastas adicionadas</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Pastas apagadas</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Abrir pasta &pai</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Navegado de Arquivos na Nuvem</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Voltar</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Avançar</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Início</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Enviar arquivos</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Enviar um diretório</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Você não tem permissões para enviar arquivos para esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Criar uma pasta</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Recarregar</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 itens</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Nome da pasta</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Nome de pasta inválido!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>O nome "%1" já está sendo utilizado.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>tentar novamente</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Falha ao obter informações dos arquivos<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Esta pasta está vazia.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Digite o nome do arquivo para salvar em...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Não foi possível remover o arquivo "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Digite o caminho da pasta que você deseja salvar em ...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Você deseja substituir o arquivo existente "% 1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Arquivo "%1" não foi sincronizado</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>O arquivo %1 já existe.<br/>Você gostaria de sobrescrever ele?<br/><small>(Escolha Não para enviar utilizando um nome alternativo)</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Arquivo não existe</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Falha ao descarregar o arquivo: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Selecione um arquivo a enviar</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Selecione um diretório para fazer o envio</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Renomear</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Você realmente quer apagar estes itens</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Criação de pasta falhou</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Falha ao fechar arquivo</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Selecione um arquivo para enviar %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Renomear falhou</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Remover falhou</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>O compartilhamento falhou</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Não é possível colar arquivos na mesma pasta</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Copiar falhou</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Mover falhou</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Falha ao criar biblioteca!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Enviar arquivo</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Enviando %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Descarregar</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Descarregando %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 de %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Operação cancelada</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>pendente</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Erro Interno do Servidor</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>Travado por %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Nome</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Tamanho</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Última Alteração</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Salvar Como...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>&Trancar</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Renomear</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Deletar</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Compartilhar com Grupo</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>At&ualizar</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Copiar</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Cor&tar</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>C&olar</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>Canc&elar o Descarregamento</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Sincronizar esta pasta</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Esta característica está disponível somente na versão pro
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Gerar %1 Link de Download</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Compartilhar com Usuário</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>G&erar %1 Link interno</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Salvar Como...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Des&Travar</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Não é Possivel remover arquivos somente leitura</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Não é possivel recortar arquivos somente leitura</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Falha ao criar pastas</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Falha ao criar arquivos temporários</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Falha ao gravar o arquivo no disco</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Falha ao remover a versão antiga do arquivo descarregado</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Falha ao mover o arquivo</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 inicializado</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Escolher %1 pasta</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Por favor escolher uma pasta</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>A inicialização não terminou. Realmente quer sair?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>A pasta %1 não existe</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logotipo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Escolher pasta</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Por favor, escolha uma pasta. Nos criaremos uma %1 subpasta para ela. Quando você descarregar uma biblioteca, ela será salva lá por padrão.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Escolher...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Próximo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Checando sua biblioteca padrão...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Criando biblioteca default...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Falhou ao criar a biblioteca padrão:
+
+A versão do servidor necessita ser 2.1 ou maior para suportar isto.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Falha ao pegar a biblioteca padrão:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Falha ao criar a biblioteca padrão:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Baixando biblioteca default...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Falha ao descarregar a biblioteca padrão:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>A biblioteca padrão foi descarregada.
+Você pode clicar no botão "Abrir" para vê-la.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Erro enquanto descarregava a biblioteca padrão: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Falha ao descarregar a biblioteca padrão:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>omitir</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Executar em segundo plano</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Abrir</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Finalizar</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Baixar biblioteca default</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logotipo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Incluir uma conta</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Re-conectar</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Logando em...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Erro de Rede:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b> Aviso: </ b> O certificado SSL deste servidor não é confiável, continuar assim mesmo?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Favor informar o endereço do servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 não é um endereço do servidor válido</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Por favor informe o nome do usuário</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Por favor, digite o nome do computador</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Favor informa a senha</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Email ou senha incorreta</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Conectando muito frequentemente, por favor, espere um minuto</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Erro Interno do Servidor</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Falla ao logar: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Falla ao logar</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logotipo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Servidor:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Por exemplo: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>ou http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Senha:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>texto de status</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Nome do Computador:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Usuário</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>e.x: Computador do Giba</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Login</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Deslogue-se Por Favor</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>Login</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Adicionar uma conta</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Atualizar</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Compatilhar %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Por favor informe o nome do grupo</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Atualizado com sucesso</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Removido com sucesso</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Falhou ao obter informação compartilhado da pasta</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Falha ao obter informação do seu grupo e contatos</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Por favor informe o nome do usuário</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>sincronizado</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexando arquivos</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>incializando sincronismo</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>baixando</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>subindo</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>mesclando</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>esperando sincronismo</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>servidor não conectado</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>autenticando servidor</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>auto sincronismo desligado</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconhecido</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erro desconhecido</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>A cota de armazenamento foi toda utilizada</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicializando...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>conectando ao servidor...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexando arquivos...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Criando pasta...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Mesclando arquivos modificados...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Feito</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Cancelando</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Cancelado</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Erro de SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Erro de Rede: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Erro do Servidor</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>falha ao abrir o banco de dados de certificados</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Arquivo "%1" não existe em "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 não pode encontrar uma aplicação para abrir o arquio %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Biblioteca criada "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Biblioteca apagada "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Renomear %1 para</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Não foi possível descarregar o item "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>falha ao copiar</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Adicionado</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Apagado</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Removido</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Modificado</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Renomeado</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Adicionado ou modificado</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Movido</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Diretório adicionado</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Diretório removido</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Diretório renomeado</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Diretório movido</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>arquivos</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>diretórios</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>e %1 mais</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Biblioteca revertida para o estado em</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Arquivo revertido "%1" para o estado em %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Diretório apagado recuperado</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Nome da biblioteca ou descrição modificada</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Agora</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 dia atrás</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 dias atrás</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 hora atrás</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 horas atrás</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 minuto atrás</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 minutos atrás</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Não faz parte do certificado></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Sincronizar esta biblioteca com:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Sincronizar esta pasta com:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Pasta</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Pasta somente leitura</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Documento</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>Documento PDF</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Arquivo de Imagem</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Documento de Texto</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Arquivo de Audio</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Arquivo de Video</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Documento Word</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>Documento PowerPoint</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Documento Excel</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>O caminhho "%1" conflita com o caminho do sistema</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>O caminhho "%1" conflita com uma biblioteca existente</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Biblioteca %1</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Esta biblioteca não foi baixada ainda</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Erro:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Icone do Repo</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Nome do Repositório</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Etiqueta</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Dono:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Última Modificação:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Tamanho:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Caminho Local:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Status:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Status Repo</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nome:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechado</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Esta biblioteca não foi baixada</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Não foi possível abrir o arquivo "% 1" da biblioteca inexistente "% 2"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Recentemente Atualizado</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Minhas bibliotecas</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sub-Bibliotecas</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Bibliotecas sincronizadas</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicializando sincronismo</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desabilitar auto sincronismo</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Habilitar auto sincronismo</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Exibir &detalhes</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Exibir detalhes desta biblioteca</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>Sincroni&zar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Sincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Recentemente Atualizado</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Si&ncronizar agora</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Sincronizar esta biblioteca imediatamente</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancelar download</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Cancelar download desta biblioteca</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Abrir pasta</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>abrir pasta local</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Desincronizar</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>desincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Ver na nuvem</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>ver esta biblioteca em Seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>Abrir &o navegador de arquivos na nuvem</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>abrir esta biblioteca no Navegador de Arquivos na Nuvem</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>&Ressincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>dessincronizar e ressincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Falha ao dessincronizar a biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Falha ao cancelar esta tarefa:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>O download foi cancelado</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Não é possível substituir o arquivo "% 1" com ele mesmo</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Não foi possível apagar o arquivo "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Falha ao enviar o arquivo: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>tentar novamente</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Falha ao buscar informações da biblioteca<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b> Aviso: </ b> O certificado SSL deste servidor não é confiável, continuar assim mesmo?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Falho ao inicializar o histórico: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Não</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar para a área de transferência</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erro desconhecido</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desabilitar auto sincronismo</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Habilitar auto sincronismo</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Sair</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Mostrar janela principal</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Configurações</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Abrir %1 &Pasta</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>abrir %1 &pasta</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Abrir pasta de &históricos</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Sobre</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Mostrar caixa de sobre da aplicação</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Ajuda online</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Arquivo</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>auto sincronismo está desabilitado</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Enviando</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Descarregando</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>abrir %1 &pasta de log</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>
+Abrir % 1 ajuda on-line</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Alguns servidores não estão conectados</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>retentar</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Falha na busca<br/>Por favor %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Status de conexão dos servidores</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>conectado</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>desconectado</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechar</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Por favor, forneça uma senha para a biblioteca</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Forneça uma senha para a biblioteca %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Por favor, digite a senha</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Senha incorreta</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erro desconhecido</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Configurações</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Nenhum</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>Proxy HTTP</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Proxy para Socks5</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Você modificou o idioma. Reiniciar para aplicá-lo?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Ocultar janela principal quando começar</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Notificar quando as bibliotecas estiverem sincronizadas</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Habilitar sincronização de arquivos temporários do MSOffice/LibreOffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Velocidade de descarga (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Velocidade de envio (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Básico</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Não dessincronizar automaticamente uma biblioteca</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Não dessincronizar automaticamente uma biblioteca quando o diretório local dela é removido ou inacessível por outras razões.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Não dessincronizar uma biblioteca quando não encontrada no servidor</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Não dessincronizar automaticamente uma biblioteca quando ela não for encontrada no servidor</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Habilitar a Extensão FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Habilitar a Extensão Explorer</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Não verificar o certificado do servidor quando sincronizando por HTTPS</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Ativar a sincronização com uma pasta existente com um nome diferente</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Avançado</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Idioma (necessita reiniciar)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Idioma</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Tipo de Proxy:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Servidor:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Porta:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Nome de usuário:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Senha:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>O servidor proxy requer uma senha</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Rede</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Compartilhar Link</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Compartilhar link:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Download direto</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Copiar para a área de transferência</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Conexão não-confiável</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 utiliza um certificado de segurança inválido. A conexão pode ser insegura. Você quer continuar?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>A chave de impressão digital RSA corrente é %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>A chave de impressão digital RSA anterior é %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Memorizar minha escolha</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Não</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Abrir</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Abrir este arquivo</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>exibir na &Web</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>ver este arquivo no site</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>retentar</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Falha ao buscar informações de arquivos estrelados<br/>Por favor %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Você não tem nenhum arquivo estrelado ainda.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Desinstalar %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Você realmente quer remover a informação da conta %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Removendo informações da conta...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>texto</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Não</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="pt_PT" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>falha ao abrir a base de dados da conta</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Tarefas de descarga</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>remover todas as tarefas de descarregadas com sucesso</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Sem tarefas de descarga neste momento.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Limpar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechar</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Biblioteca</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Caminho</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Cancelar esta tarefa</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>cancelar esta tarefa</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Remover esta tarefa</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>O cancelamento desta tarefa falhou:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Falha ao remover esta tarefa:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimizar</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechar</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>taxa de descarga atual</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>taxa de envio atual</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Por favor escolha uma pasta para sincronizar</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>nenhum servidor ligado</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>todos os servidores conectados</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>alguns servidores desconectados</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulário</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimizar</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>fechar</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Selecionar</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>taxa de descarga</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>taxa de envio</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Erro ao criar configuração de ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>falha na leitura %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Criar uma biblioteca</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Por favor escolha uma pasta</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>A criar...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Por favor escolha uma pasta para sincronizar</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>A pasta %1 não existe</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Por favor introduza o nome</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Por favor introduza a palavra-passe</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Palavras-passe não coincidem</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erro desconhecido</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Falha ao adicionar as tarefas de download:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Caminho:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Escolha</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nome:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>encriptado</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Palavra-passe:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Palavra-passe Novamente:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>texto de estado</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Por favor introduza a palavra-passe</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Sincronizar biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Falha ao adicionar tarefa de descarga:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Descarregar Biblioteca</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>escolher...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Palavra-passe para esta biblioteca:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Iniciação</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Por favor escolha uma pasta</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inicialização não completa. Deseja mesmo sair?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>A pasta %1 não existe</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Escolha...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Próximo</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>A verificar a sua biblioteca pré-definida</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>A criar a biblioteca pré-definida...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Falha ao criar a biblioteca pré-definida:
+
+A versão do servidor deve ser 2.1 ou superior para suportar isto.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>A descarregar a biblioteca pré-definida...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>A biblioteca pré-definida foi descarregada.
+Pode clicar em "Abrir" para visualizar.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Erro a descarregar a biblioteca pré-definida: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Falha ao descarregar a biblioteca pré-definida:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Avançar</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Correr em segundo plano</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Abrir</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Terminar</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Descarregar a biblioteca pré-definida</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Adicionar uma conta</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>A iniciar sessão...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Erro de rede:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Atenção:</b> O certificado SSL deste servidor não é confiável, proceder mesmo assim?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Por favor introduza o endereço do servidor</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 não é um endereço de servidor válido</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Por favor introduza um nome de utilizador</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Por favor introduza a palavra-passe</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Email ou palavra-passe incorretos</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Erro Interno de Servidor</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Início de sessão falhou: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Início de sessão falhou</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Palavra-passe:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>texto de estado</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Iniciar sessão</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Atualizar</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>sincronizado</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>A indexar ficheiros</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>A iniciar sincronização</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>A descarregar</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>A enviar</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>a fundir sincronização</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>A aguardar sincronização</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>servidor não conectado</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>servidor a autenticar</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>sincronização automática desligada</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>desconhecido</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>a inicializar...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>a establecer ligação ao servidor...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>a indexar ficheiros...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>A criar pasta...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Fundir alterações de ficheiros...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Concluído</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>A Cancelar</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Cancelado</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Esta biblioteca ainda não foi descarregada</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Erro:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Proprietário:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Alterado pela última vez em:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Tamanho:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Caminho Local:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Estado:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Nome:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechar</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Esta biblioteca não foi descarregada</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Atualizado Recentemente</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Minha Biblioteca</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Sub-bibliotecas</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desativar sincronização automática</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Ativar sincronização automática</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Sincronizar esta biblioteca imediatamente</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Cancelar descarga</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Cancelar a descarga desta biblioteca</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Abrir pasta</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>abrir pasta local</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Dessincronizar</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>dessincronizar esta biblioteca</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Ver na Cloud</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>ver esta biblioteca no seahub</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Falha ao dessincronizar a biblioteca "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Falha ao cancelar esta tarefa:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>A descarga foi cancelada</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Erro desconhecido</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Desativar sincronização automática</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Ativar sincronização automática</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Sair</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Mostrar janela principal</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Definições</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Sobre</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Mostrar a caixa Sobre da aplicação</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Ajuda online</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>sincronização automática desligada</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>alguns servidores não conectados</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Estado da conexão aos servidores</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>conectado</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>desconectado</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Fechar</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Definições</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Esconder a janela principal no início</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Notificar quando as bibliotecas forem sincronizadas</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Limitar a velocidade de download (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Limite de velocidade de envio (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Cancelar</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Desinstalar %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Deseja remover a informação da conta %1 ?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>A remover informação da conta...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Diálogo</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>texto</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Sim</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Não</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="ru" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>О %1</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation><h2>%1 Клиент %2</h2></translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> REV %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>О программе</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>Проверить обновления</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>Не удалось открыть базу данных аккаунтов</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Авторизация истекла. Пожалуйста, войдите снова</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>Не удалось удалить токен синхронизации локального репозитория: %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>Не удалось получить информацию о синхронизации репозитория от сервера: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Настройки аккаунта</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Пожалуйста, введите адрес сервера</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 - неправильный адрес сервера</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Не удалось сохранить информацию об аккаунте</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Не удалось сохранить изменения: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Текущая информация об аккаунте успешно обновлена</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Адрес сервера</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Email</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>Вы действительно хотите удалить аккаунт %1?<br><br>Аккаунт будет удален локально. Вся конфигурация синхронизации также будет удалена. Это не повлияет на аккаунт на сервере.</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Не удалось рассинхронизировать библиотеки этого аккаунта: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>Нажмите, чтобы открыть веб-сайт</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>Pro версия</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Нет аккаунта</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Выберите</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Настройки аккаунта</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Войти</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Удалить</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Добавить аккаунт</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Выйти</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>Вход не выполнен</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Аккаунт</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>email</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>сервер</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>Файловая активность доступна только в %1 Server Professional Edition.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>повторить</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Не удалось получить данные об активности. Пожалуйста, %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Успешно загружено</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Файл "%1"
+успешно загружен.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Файл "%1"
+не удалось загрузить.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Ошибка доступа!</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Авторизация истекла</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Файл не существует</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>Файл заблокирован %1, пожалуйста, попробуйте позже</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>Ошибка загрузки: %1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Не удалось создать папку для аватаров</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>Проверка разрешения</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Задачи на скачивание</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>Удалить все успешно завершенные задания</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Сейчас нет задач на скачивание</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Очистить</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Библиотека</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Путь</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Отменить это задание</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>Отменить это задание</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Удалить это задание</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Не удалось отменить задание:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Не удалось удалить задание:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Свернуть</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Библиотеки</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Избранное</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Активность</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Поиск</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>Текущая скорость скачивания</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>Текущая скорость загрузки</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Выберите папку для синхронизации</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>Нет подключенных серверов</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>Все серверы подключены</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Некоторые серверы не подключены</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>логотип</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>Свернуть</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>Закрыть</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Выбор</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>бренд</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>или перетащите сюда папку для синхронизации</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>Скорость скачивания</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>стрелка вниз</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>Скорость загрузки</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>стрелка вверх</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Ошибка при создании конфигурации ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Невозможно создать папку предварительной настройки "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>Не удалось прочитать %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Создать библиотеку</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Выберите папку</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Создание...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Не удалось создать ключ шифрования для этой библиотеки</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Выберите папку для синхронизации</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Папка %1 не существует</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Введите имя</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Введите пароль</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Пароли не совпадают</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Не удалось добавить задачу на скачивание:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Не удалось создать библиотеку на сервере:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Путь:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Выберите</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Имя:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>зашифровано</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Пароль:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Пароль повторно:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>текст статуса</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 клиент не удалось инициализировать</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1 неожиданно вышел</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Введите пароль</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Синхронизация библиотеки "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Синхронизация папки "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Синхронизировать с папкой:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>или</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>синхронизировать с существующей папкой</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>создать новую папку для синхронизации</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Синхронизировать с этой существующей папкой:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Пожалуйста, выберите папку</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Папка не существует</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Пожалуйста, выберите папку для синхронизации.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Ваша организация отключила вставку в библиотеку за пределы папки %1.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Конфликтует с существующим файлом "%1", выберите другую папку.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Конфликтует с существующей библиотекой "%1", выберите другую папку.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>Папка "%1" уже существует. Действительно синхронизировать с ней (содержимое будет объединено)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Нажмите Нет для синхронизации с новой папкой вместо этого</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Невозможно найти другое имя папки</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Не удалось добавить задачу на скачивание:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Не удалось получить информацию о репозитории для скачивания
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Скачать библиотеку</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>выберите...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Пароль для этой библиотеки:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Подробности изменения</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Добавленные файлы</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Удаленные файлы</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Измененные файлы</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Добавленные файлы</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Удаленные папки</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Открыть</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Открыть &родительскую папку</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Файловый менеджер</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Назад</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>Вперед</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Домой</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Загрузить файлы</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Загрузить папку</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>У вас нет доступа для загрузки файлов в эту библиотеку</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Создать папку</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>Обновить</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 элементов</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Имя папки</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Неправильное имя папки!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>Имя "%1" уже занято.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>повторить</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Не удалось получить информацию о файлах.<br/>Пожалуйста, %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>Эта папка пуста.</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Введите имя файла, чтобы сохранить в...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>Невозможно удалить файл "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Введите путь к папке, в которую хотите сохранить...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>Действительно перезаписать существующий файл "%1"?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>Файл "%1" не был синхронизирован</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Файл %1 уже существует.<br/>Хотите перезаписать его?<br/><small>(Выберите Нет, чтобы загрузить файл под другим именем).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>Файл не существует</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Не удалось скачать файл: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Выберите файл для загрузки</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Выберите папку для загрузки</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Переименовать</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Вы точно хотите удалить эти элементы</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Не удалось создать папку</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>Не удалось заблокировать</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Выберите файл для обновления %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Не удалось переименовать</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Не удалось удалить</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Не удалось предоставить доступ</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Нельзя вставить файлы в ту же папку</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>Нельзя вставить папку в свою подпапку</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Не удалось скопировать</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Не удалось переместить</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Не удалось создать библиотеку!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>У вас нет доступа для загрузки в эту папку</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Авторизация истекла</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Ошибка доступа!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Библиотека/Папка не найдена.</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>Не удалось загрузить файл %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>Невозможно создать папку кэша</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>Невозможно открыть папку кэша</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>Поиск файлов</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Не удалось получить ссылку</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>Не удалось получить информацию о ссылке для загрузки файла "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>Ожидаем</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Загрузить</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Загрузка %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>Скачать</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>Скачивание %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 из %2</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>Не удалось загрузить файл "%1", повторить попытку?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>Повторить</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Пропустить</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>Отменить</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>Сохранение</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>Не удалось сохранить файл</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>Ошибка запроса прогресса индекса %1</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>Имя</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Размер</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Последнее изменение</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Показать в папке</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Показать в папке</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>Операция отменена</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>ожидаем</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>задача отменена</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Внутренняя ошибка сервера</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Квота хранения была израсходована</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>заблокировано %1</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>Имя</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Размер</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>Последнее изменение</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>Модификатор</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Сохранить как...</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>Заблокировать</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Переименовать</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Удалить</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>Поделиться с группой</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Обновить</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Копировать</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>Выре&зать</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>Вставит&ь</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>От&менить скачивание</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Синхронизировать эту папку</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Эта функция доступна только в Pro версии
+</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>&Создать ссылку общего доступа</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>Поделиться с пользователем</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>Создать %1 внутреннюю ссылку</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Сохранить как...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>Разблокировать</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Невозможно удалить файлы только для чтения</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Невозможно вырезать файлы только для чтения</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>Повторить загрузку</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>Удалить локальную версию</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>Сохранить локальную версию как...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>Открыть локальную папку кэша</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation>&Создать %1 ссылку для загрузки</translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation>Не удалось получить ссылку</translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation>Файл "%1" заблокирован %2</translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation>Не удалось получить информацию о блокировке файла "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation>Не удалось получить ссылку для загрузки файла "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Не удалось создать папки</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Не удалось создать временные файлы</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Не удалось записать файл на диск</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>Не удалось удалить предыдущую версию скачанного файла</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Не удалось переместить файл</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 инициализация</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>Выберите %1 папку</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Выберите папку</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Инициализация не закончена. Действительно выйти?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Папка %1 не существует</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>заставка</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>Выберите папку</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>Выберите папку. В ней будет создана подпапка %1. Скачанные библиотеки будут сохранены там по умолчанию.</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Выберите...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Дальше</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 хранит файлы в библиотеках.
+Хотите скачать библиотеку по умолчанию?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Проверка вашей библиотеки по умолчанию</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Создание библиотеки по умолчанию...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Не удалось создать библиотеку по умолчанию:
+
+Для выполнения данной операции версия сервера должна быть 2.1 или выше.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Не удалось получить библиотеку по умолчанию:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Не удалось создать библиотеку по умолчанию.
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Скачивание библиотеки по умолчанию...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Не удалось скачать библиотеку по умолчанию:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Скачивание библиотеки по умолчанию завершено.
+Для ее просмотра можете нажать кнопку "Открыть".</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Ошибка при скачивании библиотеки по умолчанию: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Не удалось скачать библиотеку по умолчанию:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1 хранит файлы в библиотеках.
+Хотите скачать библиотеку по умолчанию?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Пропустить</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Выполнять как фоновую задачу</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Открыть</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Конец</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Скачать библиотеку по умолчанию</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>заставка</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>загрузить еще</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>Не удалось загрузить лог файлы</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Загрузка лог файлов</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>Ошибка доступа!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>Библиотека/Папка не найдена.</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>Авторизация истекла</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>Не удалось загрузить лог файлы :%1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>Лог файлы успешно загружены</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>Сжатие</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 из %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Добавить аккаунт</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>Единая точка входа</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>Войти заново</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Авторизуемся...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Сетевая ошибка:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Внимание:</b> SSL-сертификат этого сервера не является доверенным. Продолжить несмотря на это?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Введите адрес сервера</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 неправильный адрес сервера</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Введите имя пользователя</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Пожалуйста, введите имя компьютера</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 Адрес сервера</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>Адрес сервера не должен быть пустым.</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 неправильный адрес сервера. Должен начинаться на 'https://'</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Введите пароль</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Неверный email или пароль</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Слишком частые попытки входа. Пожалуйста, подождите минуту</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Внутренняя ошибка сервера</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Не удалось авторизоваться: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Не удалось авторизоваться</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>заставка</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Сервер:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Например: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>или http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Пароль:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>текст статуса</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Имя компьютера: </translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>Email / Имя пользователя:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>Например, Ноутбук Ивана</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Логин</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>Автоматический вход</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Вы вышли. Пожалуйста, </translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>логин</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Добавить аккаунт</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Обновить</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>%1 синхронизирован</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>Файлы загружены в "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>Не удалось синхронизировать файл %1
+Файл заблокирован другим приложением. Этот файл будет обновлен после закрытия приложения.</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>Не удалось синхронизировать папку %1
+Какой-то файл в этот папке заблокирован другим приложением. Эта папка будет обновлена после закрытия приложения.</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>Не удалось синхронизировать файл %1
+Файл заблокирован другим пользователем. Обновление для этого файла не загружено.</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>Не удалось проиндексировать файл %1
+Пожалуйста, проверьте разрешения файла и дисковое пространство.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>Не удалось синхронизировать %1
+Путь к файлу заканчивается пробелом или точкой и не может быть создан в Windows.</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>Не удалось синхронизировать %1
+Путь к файлу содержит недопустимые символы. Это не синхронизировано с этим компьютером.</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>Обновление файла %1 запрещено настройками разрешений папки.</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>Нет разрешения на синхронизацию папки %1.</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation>Обновления в библиотеке %1 только для чтения не будут загружены.</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation>Одновременные обновления в файл. Файл %1 сохранен как файл конфликта</translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation>Папка %1 перемещена в папку seafile-recycle-bin, т.к. она содержит еще не загруженные файлы.</translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation>Папка для библиотеки %1 удалена или перемещена. Библиотека не синхронизирована.</translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>Поделиться %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>Введите имя группы</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>Введите имя пользователя или email адрес</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>Успешно обновлено</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>Не удалось предоставить общий доступ: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>Успешно удалено</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>Не удалось получить информацию об общей папке</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>Не удалось получить информацию о ваших группах и контактах</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Введите имя пользователя</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>Введите имя группы</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>Нет такой группы "%1"</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>Уже поделились с группой %1</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>Уже поделились с пользователем %1</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Предыдущая операция все еще выполняется</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>Поделиться с:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>Поделиться</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>Разрешение:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>Чтение-Запись</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>Только для чтения</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>Синхронизировано</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>индексация файлов</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>инициализация синхронизации</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>Скачивание</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>Загрузка</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>синхронизация</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>ожидание синхронизации</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>Сервер не подключен</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>идентификация сервера</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>автоматическая синхронизация отключена</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>Неизвестно</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>Ошибка сети</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>Не удалось определить адрес прокси-сервера</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>Не удалось определить адрес сервера</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>Не удалось соединиться с сервером</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>Не удалось установить безопасное соединение. Пожалуйста, проверьте SSL сертификат сервера</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>Передача данных была прервана. Пожалуйста, проверьте сеть или брандмауэр</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>Передача данных прервана по тайм-ауту. Пожалуйста, проверьте сеть или брандмауэр</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>Неправильное HTTP перенаправление сервера. Пожалуйста, проверьте конфигурацию сервера</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>Ошибка сервера</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>Недостаточно памяти</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>Не удалось записать данные о клиенте. Пожалуйста, проверьте дисковое пространство или разрешения для папки</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>Квота хранения заполнена</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>Библиотека удалена на сервере</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>Библиотека повреждена на сервере</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Квота хранения была израсходована</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Инициализация...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>соединение с сервером...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>индексация файлов...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>Скачивание списка файлов...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>Скачивание файлов...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Создание папки...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Слияние изменения файлов ...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Готово</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>проверка информации о сервере...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Отменяется</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Отменено</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>Ошибка SSL</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Сетевая ошибка: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Ошибка сервера</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>Не удалось открыть базу сертификатов</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>Файл "%1" не существует в "%2"</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 не смог найти приложение для открытия файла %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>Создана библиотека "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>Удалена библиотека "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>Переименовать %1 в</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>Невозможно скачать элемент "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>Не удалось скопировать</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Добавлен</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Удален</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Удален</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Изменен</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Переименован</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Добавлено или изменено</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Перемещен</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Добавлена папка</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Удалена папка</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Переименованная папка</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Папка перемещена</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>файлы</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>папки</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>и еще %1</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Библиотека возвращена к статусу от</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>Файл "%1" возвращен к статусу от %2.</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Удаленная папка восстановлена</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Изменено имя или описание библиотеки</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>Авто слияние с %1 системой</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Только что</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 день назад</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 день назад</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 час назад</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 часов назад</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 минуту назад</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 минуту назад</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Не часть сертификата></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>>Синхронизировать эту библиотеку с:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Синхронизировать эту папку с:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Папка</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Папка только для чтения</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Документ</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF документ</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>Изображение</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Текстовый документ</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Аудио файл</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Видео файл</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word документ</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint документ</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel документ</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>Путь "%1" конфликтует с системным путем</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>Путь "%1" конфликтует с существующей библиотекой</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>загрузка списка файлов</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>Файл заблокирован другим приложением</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>Папка заблокирована другим приложением</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>Файл заблокирован другим пользователем</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>Путь неверный</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>Ошибка при индексации</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>Путь заканчивается пробелом или точкой</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>Путь содержит недопустимые символы, такие как '|' или ':'</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>Не удалось открыть базу данных кэша</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>Имя библиотеки содержит недопустимые символы, такие как ':', '*', '|', '?'</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>Обновление файла запрещено настройками разрешений папки</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>%1 клиент уже запущен</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>Внутренние данные повреждены на клиенте. Пожалуйста, попробуйте повторно синхронизировать библиотеку</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>Нет разрешения на запись в библиотеку</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>Нет разрешения на синхронизацию этой папки</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>Удалены все объекты из корзины</translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>Удалены объекты старше %1 дней из корзины</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>Черновик опубликован</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>Черновик создан</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>Файл создан</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>Файл переименован</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>Черновик удален</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>Файл удален</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>Файл восстановлен</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>Файл перемещен</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>Файл обновлен</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>Папка создана</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>Папка переименована</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>Папка удалена</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>Папка восстановлена</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>Папка перемещена</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>Библиотека создана</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>Библиотека переименована</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>Библиотека удалена</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>Библиотека восстановлена</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>Создан или обновлен файл в недоступной для записи библиотеке или папке</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>Доступ запрещен на сервере</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>Одновременные обновления в файл. Файл сохранен как файл конфликта</translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>Папка, которая может содержать еще не загруженные файлы, перемещена в папку seafile-recycle-bin.</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation>не удалось открыть базу данных с кодом ошибки синхронизации</translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>Файл не существует</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Библиотека "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Эта библиотека еще не скачивалась</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Ошибка: </translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>каждые %1 сек.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Значок репозитория</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Имя репозитория</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Метка</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Владелец:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Последнее изменение:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>Время изменения</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Размер:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Локальный путь:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Статус:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Статус репозитория</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Имя:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>Интервал синхронизации:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Эта библиотека не может быть скачана</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Невозможно открыть файл "%1" из несуществующей библиотеки "%2"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Последние обновления</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Мои библиотеки</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Суб-библиотеки</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>Поделились со мной</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>Поделились со всеми</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>Поделились с группами</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Синхронизированные библиотеки</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>инициализация синхронизации</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Отключить автоматическую синхронизацию</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Включить автоматическую синхронизацию</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Показать &подробности</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Показать подробности о библиотеке</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Синхронизировать эту библиотеку</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Синхронизировать эту библиотеку</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Недавно обновленные</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Синхронизировать &сейчас</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Синхронизировать эту библиотеку немедленно</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>От&мена скачивания</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Отмена скачивания этой библиотеки</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Открыть папку</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>открыть локальную папку</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>&Открыть локальную папку</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Рассинхронизировать</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Рассинхронизировать эту библиотеку</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Открыть в браузере</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>Открыть эту библиотеку в браузере</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>Поделиться с пользователем</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>Поделиться этой библиотекой с пользователем</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>Поделиться с группой</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>Поделиться этой библиотекой с группой</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Открыть встроенный файловый менеджер</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>открыть эту библиотеку во встроенном файловом менеджере</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>&Покинуть общий доступ</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>оставить общий доступ</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>Рес&инхронизировать эту библиотеку</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>Рассинхронизировать и ресинхронизировать эту библиотеку</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>Установить интервал синхронизации</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>Установить интервал синхронизации для этой библиотеки</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>Вы уверены, что хотите рассинхронизировать библиотеку "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>Вы уверены, что хотите пересинхронизировать библиотеку "%1"?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>Вы уверены, что хотите перезаписать файл "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Не удалось рассинхронизировать библиотеку "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>Вы уверены, что хотите оставить общий доступ "%1"?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>Не удалось оставить общий доступ</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Не удалось отменить эту задачу: %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Скачивание было отменено</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>У вас нет доступа для загрузки в эту папку</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>Невозможно перезаписать файл "%1" с самим собой</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>Не удалось удалить файл "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Не удалось загрузить файл: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>Интервал синхронизации (в секундах):</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>Установить интервал синхронизации для библиотеки "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>Поиск библиотек</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>повторить</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Не удалось получить информацию о библиотеках.<br/>Пожалуйста, %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Внимание:</b> SSL-сертификат этого сервера не является доверенным, в любом случае продолжить?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Ошибка инициализации лога: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Нет</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>не удалось сохранить идентификатор клиента</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>не удалось получить доступ к %1</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>неверный идентификатор клиента</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>не удалось прочитать %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 Внутренняя ссылка</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Копировать в буфер обмена</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>%1 Внутренняя ссылка:</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>%1 ссылка для доступа к рабочему столу:</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>внутренняя ошибка: не удалось подключиться к демону</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Отключить автоматическую синхронизацию</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Включить автоматическую синхронизацию</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Выход</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Показать главное окно</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Настройки</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Открыть &папку %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>открыть папку %1</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>Открыть папку с &логами</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>Показать ошибки синхронизации файлов</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>О &программе</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Показать окно About</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Онлайн справка</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Файл</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>автоматическая синхронизация отключена</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Загрузка</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>Скачивание</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>открыть папку %1 с логами</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>открыть %1 онлайн справку</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>Некоторые серверы не подключены</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>Загрузка лог файлов</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>загрузка %1 лог файлов</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>Пожалуйста, сначала войдите</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>Исправить расширение проводник</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>Успешно исправлены значки состояния синхронизации для проводника</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>Не удалось исправить значки состояния синхронизации для проводника</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>есть некоторые ошибки при синхронизации</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>&Показать в папке</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>Показать в папке</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>Поиск файлов</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>повторить</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>Не удалось найти<br/>Пожалуйста %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Статус соединения серверов</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>подключено</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>отключено</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрыть</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Пожалуйста, укажите пароль к библиотеке</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>Укажите пароль для библиотеки %1</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Пожалуйста, введите пароль</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Неверный пароль</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Неизвестная ошибка</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Настройки</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>Автоматически запускать %1 после входа в систему</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>Спрятать иконку %1 из трея</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Нет</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP прокси</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 прокси</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>Системный прокси</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Вы изменили язык. Перезапустить приложение сейчас?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>Хост прокси не может быть пустым</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>Порт прокси неправильный</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>Имя пользователя прокси не может быть пустым</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>Пароль прокси не может быть пустым</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Скрыть главное окно при запуске приложения</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Уведомить о синхронизации библиотек</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>Синхронизировать временные файлы MSOffice/Libreoffice</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Ограничение скорости скачивания (КБ/с):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Ограничение скорости загрузки (КБ/с):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Основной</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Не рассинхронизировать библиотеку автоматически</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Не рассинхронизировать библиотеку автоматически, когда локальная папка была удалена или стала недоступна по другим причинам.</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Не рассинхронизировать библиотеку, когда она не была найдена на сервере</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Не рассинхронизировать библиотеку автоматически, когда она не была найдена на сервере</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>Включить расширение FinderSync</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Включить расширение проводник</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>Автоматическая проверка обновлений</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>Не проверять сертификат сервера при HTTPS синхронизации</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Включить синхронизацию для папки с другим именем</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Дополнительно</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Язык (необходим перезапуск)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Язык</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Тип прокси:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Хост:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Порт:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Имя пользователя:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Пароль:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Прокси сервер требует пароль</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Сеть</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>Чтение Запись</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Только для чтения</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>Удалить общий доступ</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>Нажмите, чтобы изменить</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>Создано %1</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>Чтение Запись</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>Только для чтения</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>Группа</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>Пользователь</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>Разрешение</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>Предыдущая операция все еще выполняется</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Ссылка</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Ссылка:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Прямое скачивание</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Копировать в буфер обмена</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation>Ссылка для загрузки</translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation>Ссылка для загрузки:</translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Недоверенное соединение</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 использует недействительный сертификат безопасности. Соединение может быть небезопасным. Вы желаете продолжить?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Текущий отпечаток RSA %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Предыдущий отпечаток RSA %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Запомнить мой выбор</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Нет</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Открыть</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Открыть этот файл</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>Посмотреть на &веб-сайте</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>Посмотреть этот файл на веб-сайте</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>повторить</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Не удалось получить информацию об избранных файлах.<br/>Пожалуйста, %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>У вас еще нет избранных файлов.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>Ошибки синхронизации файлов</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>Нет ошибок синхронизации.</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>Дважды щелкните, чтобы открыть библиотеку</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>Библиотека</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Путь</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>Ошибка</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>Время</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>Введите токен двухфакторной аутентификации</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>Двухфакторная аутентификация</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>Пожалуйста, введите токен двухфакторной аутентификации</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>Запомнить это устройство</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Отмена</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>ОК</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Деинсталляция %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Желаете удалить информацию об аккаунте %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Удаление информации об аккаунте...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Диалог</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>текст</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Да</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Нет</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="sk_SK" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>nepodarilo sa otvoriť databázu s účtami</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Úlohy na stiahnutie</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>zmazať všetky úspešné úlohy</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Momentálne nie sú žiadne úlohy na stiahnutie. </translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Vyčistiť</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavrieť</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Knižnica</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Cesta</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Zrušiť túto úlohu</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>zrušiť túto úlohu</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Odobrať túto úlohu</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Nepodarilo sa zrušiť úlohu:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Nepodarilo sa odobrať úlohu:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Minimalizovať</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavrieť</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>aktuálna rýchlosť sťahovania</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>aktuálna rýchlosť nahrávania</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Prosím vyberta adresár pre synchronizáciu</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>nie je pripojený žiadny server</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>všetky servery sú pripojené</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>niektoré servery nie sú pripojené</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Formulár</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>minimalizovať</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>zatvoriť</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Vybrať</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>alebo vyberte adresár, ktorý chcete synchronizovať</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>rýchlosť sťahovania</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>šípka dole</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>rýchlosť nahrávania</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>šípka hore</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Chyba pri vytvárani ccnet konfigurácie</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>nepodarilo sa prečítať %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Vytvoriť knižnicu</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Prosím vyberte adresár</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Vytváram...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Prosím vyberte adresár na synchronizáciu</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Adresár %1 neexistuje</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Prosím vložte meno</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Prosím vložte heslo</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Heslá nie sú rovnaké</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Neznáma chyba</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Nepodarilo sa pridať úlohu na stiahnutie:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Cesta:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Vyber</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Meno:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>zašifrovaná</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Heslo:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Heslo znova:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>text stavu</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušiť</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Prosím vložte heslo</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Synchronizovať knižnicu "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Nepodarilo sa pridať úlohu na stiahnutie:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Stiahnuť knižnicu</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>vyber...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Heslo pre túto knižnicu:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušiť</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 Inicializácia</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Prosím vyberte adresár</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Inicializácia nie je ukončená. Naozaj odísť?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Adresár %1 neexistuje</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Vyber...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Ďaľší</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušiť</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Kontrolujem predvolenú knižicu</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Vytváram predvolenú knižnicu...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Nepodarilo sa vytvoriť predvolenú knižnicu
+
+Server musí byť verzie 2.1 alebo vyššie pre túto funkcionalitu.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Sťahujem predvolenú knižnicu...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Predvolená knižnica bola stiahnutá.
+Pre zobrazenie môžete kliknúť na tlačítko "Otvoriť".</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Chyba pri sťahovaní predvolenej knižnice: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Nepodarilo sa stiahnuť predvolenú knižnicu:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialógové okno</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Preskočiť</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Bežať na pozadí</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Otvoriť</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Koniec</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Stiahnutie predvolenej knižnice</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Áno</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Pridať účet</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Prihlasujem...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Sieťová chyba:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Upozornenie:</b> SSL certifikát servera nie ne dôveryhodný, pokračovať?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Prosím zadajte adresu servera</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 nie je platná adresa servera</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Prosím zadajte užívateľské meno</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Prosím zadajte heslo</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Neplatná mailová adresa alebo heslo</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Interná chyba na servery</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Nepodarilo sa prihlásiť: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Nepodarilo sa prihlásiť</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Heslo:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>text stavu</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Prihlásiť</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušiť</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Obnoviť</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>zosynchronizované</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>indexujem súbory</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>inicializácia synchronizácie</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>sťahujem</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>nahrávam</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>spájam synchronizáciu</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>čakám na synchronizáciu</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>server nie je pripojený</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>overujem server</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>automatická synchronizácia je vypnutá</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>neznáme</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>inicializácia...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>pripájanie na server...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>indexujem súbory...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Vytváram adresár...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Spájam zmeny súborov...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Ukončené</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Ruším</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Zrušené</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Knižnica "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Táto knižnica ešte nebola stiahnutá</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Chyba:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>RepoIcon</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>RepoName</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>TextLabel</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Vlastník:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Naposledy zmenené:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Veľkosť:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Lokálna cesta:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Stav:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>RepoStatus</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Meno:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zatvoriť</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Táto knižnica nebola stiahnutá</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Nedávno aktualizované</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Moje Knižnice</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Vnorené knižnice</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Vypnúť automatickú synchronizáciu</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Zapnúť automatickú synchronizáciu</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Túto knižnicu synchronizovať okamžite</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Prerušiť sťahovanie</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Prerušiť preberanie tejto knižnice</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Otvor priečinok</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>otvor lokálny priečinok</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Odsynchronizavať</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>odsynchronizovať túto knižnicu</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Pozri v cloude</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>pozri túto knižnicu v seahube</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Nepodarilo sa odsynchronizovať knižnicu "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Nepodarilo sa zrušiť úlohu:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Preberanie bolo zrušené</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Neznáma chyba</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Vypnúť automatickú synchronizáciu</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Zapnúť automatickú synchronizáciu</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Ukončiť</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Zobraziť hlavné okno</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Nastavenia</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&O aplikácii</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Zobraziť dialóg O aplikácii</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Online pomoc</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>automatická synchronizácia je vypnutá</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>niektoré servery nie sú pripojené</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Stav pripojenia serverov</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>pripojený</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>odpojený</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Zavrieť</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Nastavenia</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Po spustení skryť hlavné okno</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Upozorniť keď sú knižnice synchronizované</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Limit rýchlosti sťahovania (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Limit rýchlosti nahrávania (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Zrušiť</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Odinštalovať %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Chcete odstrániť informácie o účte %1?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Odstraňujem informácie o účte...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialóg</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>text</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Áno</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nie</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="sv" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>kunde inte öppna kontodatabas</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Behörighet har löpt ut, logga in igen</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Kontoinställningar</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Ange serveradressen</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 är inte en giltig serveradress</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Det gick inte att spara kontoinformation</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Det gick inte att spara ändringarna: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Uppdaterade aktuell kontoinformation</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Serveradress</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>E-postadress</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>klicka för att öppna webbsidan</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>pro-version</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Inget konto</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Välj</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Kontoinställningar</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Logga in</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Ta bort</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Lägg till konto</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Logga ut</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>inte inloggad</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>e-postadress</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>server</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>ingen server ansluten</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>alla servrar anslutna</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>vissa servrar inte anslutna</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>stäng</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Välj</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>eller släpp mapp för att synkronisera</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>nedladdningshastighet</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>uppladdningshastighet</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Kunde inte skapa ccnet-konfiguration</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>kunde inte läsa %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Skapa en katalog</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Välj en katalog</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Skapar...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>Kunde inte skapa en krypteringsnyckel för den här katalogen</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Okänt fel</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>OK</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Avbryt</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Lägg till konto</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Uppdatera</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>text</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Ja</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Nej</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="tr" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>hesap veritabanı açılamadı</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>Yetkilendirme süresi doldu, lütfen yeniden giriş yapın.</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>Hesap Ayarları</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Lütfen sunucu adresini girin</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 geçerli bir sunucu adresi değil</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>Hesap bilgileri kaydedilemedi</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>Değişiklikler kaydedilemedi: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>Mevcut hesap bilgileri başarıyla güncellendi</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>Sunucu Adresi</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>Eposta</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal et</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>Hesaba ait kütüphanelerin senkronizasyonu durdurulamadı: %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>websitesini açmak için tıklayın</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>pro versiyon</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>Hesap yok</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Seç</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>Hesap ayarları</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Giriş yap</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>Sil</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Bir hesap ekleyin</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>Çıkış yap</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>giriş yapılmadı</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>Hesap</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>eposta</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>sunucu</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>tekrar dene</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>Etkinlikler bilgisi alınamadı. Lütfen %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>Yükleme başarılı</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>Dosya "%1"
+başarıyla yüklendi.</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>Dosya "%1"
+yüklenemedi.</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>Avatar klasörü oluşturma başarısız</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>İndirme görevleri</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>tüm başarılı görevleri kaldır</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Şu anda indirme görevi yok.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Temizle</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Kapat</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Kütüphane</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Yol</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Bu görevi iptal et</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>bu görevi iptal et</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Bu görevi kaldır</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Bu görev iptal edilemedi:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Bu görev kaldırılamadı:
+
+ %1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Küçült</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Kapat</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>Kütüphaneler</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>Yıldızlı</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>Etkinlikler</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>Ara</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>güncel indirme oranı</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>güncel yükleme oranı</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Lütfen senkronize etmek için bir klasör seçiniz</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>bağlı sunucu yok</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>tüm sunucular bağlı</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>bazı sunucular bağlı değil</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>küçült</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>kapat</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Seç</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>ya da Sürükle</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>indirme oranı</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>aşağı ok</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>yükleme oranı</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>yukarı ok</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>ccnet konfigürasyonu oluşturulurken hata </translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>Ön yapılandırma dizini "%1" oluşturulamıyor
+</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>okuma başarısız %1 </translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Bir kütüphane oluştur</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Lütfen bir dizin seçin</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Oluşturuyor...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Lütfen senkronize edilecek dizini seçin</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Klasör %1 yok</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Lütfen isim giriniz</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lütfen şifreyi giriniz</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Şifreler eşleşmiyor</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Bilinmeyen hata</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>İndirme görevi ekleme başarısız:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>Sunucuda kütüphane oluşturma başarısız:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Yol:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Seç</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>İsim:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>şifreli</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Şifre:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Şifre Tekrar:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>durum metni</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal et</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lütfen şifreyi girin</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Kütüphaneyi Senkronize et "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>Senkronizasyon klasörü "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>Klasöre senkronize et:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>ya da</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>mevcut bir klasörle senkronize et</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>yeni bir senkronizasyon klasörü oluştur</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>Bu mevcut klasörle senkronize et:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>Lütfen bir klasör seçin</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>Klasör mevcut değil</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>Lütfen senkronize edilecek klasörü seçin.</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>Organizasyonunuz %1 klasörü dışına kütüphane koyulmasını engelliyor.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>Mevcut "%1" dosyası ile uyuşmazlık var, lütfen başka bir klasör seçin.</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>Mevcut "%1" kütüphanesi ile uyuşmazlık var, lütfen başka bir klasör seçin.</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>"%1" klasörü zaten var. Onunla senkronize etmek istediğinize emin misiniz (içerikler birleştirilecek)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>Yeni bir klasörle senkronize etmek için Hayır'ı tıklayın</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>Alternatif bir klasör ismi bulunamıyor</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>İndirme görevi ekleme başarısız:
+ %1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>Repo indirme bilgisi alınamadı:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Kütüphaneyi İndir</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>seç...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Bu kütüphane için şifre:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal Et</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>Değiştirme Ayrıntıları</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>Eklenen dosyalar</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>Silinen dosyalar</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>Değiştirilen dosyalar</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>Eklenen klasörler</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>Silinen klasörler</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Aç</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>Aç &ebeveyn klasör</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>Bulut Dosya Tarayıcısı</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>Geri</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>İlet</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>Anasayfa</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>Dosyaları yükle</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>Bir dizin yükle</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>Bu kütüphaneye dosya yüklemek için izniniz yok</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>Bir klasör oluşturun</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>Klasör adı </translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>Geçersiz klasör adı!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>"%1" ismi daha önce alınmış.</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>tekrar deneyin</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>Dosya bilgileri alınamadı<br/>Lütfen %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>Kaydetmek için dosya adını girin</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>"%1" dosyası kaldırılamıyor</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>Kaydetmek istediğiniz klasör yolunu girin...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>"%1" dosyasının üzerine yazmak istiyor musunuz?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>"%1" dosyası senkronize edilmedi</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>Dosya %1 zaten var.<br/>Üstüne yazmak ister misiniz?<br/><small>(Başka bir isim kullanarak yüklemek için Hayır seçin).</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>Dosya indirme başarısız: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>Yüklemek için bir dosya seçin</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>Yüklemek için bir dizin seçin</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>Yeniden adlandır</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>Bu öğeleri silmeyi gerçekten istiyor musunuz?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>Klasör oluşturma başarısız</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>Güncellemek için bir dosya seç %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>Yeniden adlandırılamadı</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>Taşıma başarısız</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>Paylaşma başarısız</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>Aynı klasörden dosyalar yapıştırılamaz</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>Kopyalama başarısız</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>Taşıma başarısız</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>Kütüphane oluşturma başarısız!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal et</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>Yükle</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>Yüklüyor %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>İndir</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>İndiriyor %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%2 de %1</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>İşlem iptal edildi.</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>beklemede</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>İç Sunucu Hatası</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>İsim</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>Boyut</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>En son Değiştirme</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>&Farklı kaydet</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>&Yeniden Adlandır</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>&Sil</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>&Güncelle</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>&Kopyala</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>&Kes</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>&Yapıştır</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>&İndirmeyi iptal et</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>&Bu klasörü senkronize et</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>Bu özellik sadece pro versiyonda mevcut</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>&Buraya farklı kaydet...</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>Salt okunur dosyalar kaldırılamıyor</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>Salt okunur dosyalar kesilemiyor</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>Klasör oluşturma başarısız</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>Geçici dosya oluşturma başarısız</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>Dosyayı diske yazma başarısız</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>İndirilen dosyanın eski versiyonu kaldırılamadı</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>Dosya kaldırılamadı</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 başlatma</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Lütfen bir dizin seçin</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Başlatma henüz bitmedi. Gerçekten çıkıyor musunuz?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Klasör %1 yok</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Seç...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Sonraki</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal et</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Varsayılan kütüphanenizi kontrol ediyor...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Varsayılan kütüphane oluşturuluyor...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Varsayılan kütüphane oluşturma başarısız:
+
+Bu işlemin desteklenmesi için Sunucu versiyonu 2.1 ya da daha yüksek olmalı.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>Varsayılan kütüphaneyi alma başarısız:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>Varsayılan kütüphane oluşturma başarısız:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Varsayılan kütüphane indiriliyor...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>Varsayılan kütüphaneyi indirme başarısız:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Varsayılan kütüphane indirildi.
+Görüntülemek için "Aç" düğmesine basabilirsiniz.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Varsayılan kütüphane indirilirken hata oluştu: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Varsayılan kütüphaneyi indirme başarısız oldu:
+ %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Atla</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Arka planda yürüt</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Aç</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Son</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Varsayılan Kütüphaneyi İndir</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Evet</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Hesap ekle</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>yeniden giriş yapın</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Giriş yapıyor...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Ağ Hatası:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Uyarı:</b> Bu sunucunun ssl sertifikası güvenilir değil, yine de devam edilsin mi?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Lütfen sunucu adresini giriniz</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 geçerli bir sunucu adresi değil</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>lütfen kullanıcı adını giriniz</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Lütfen bilgisayar adını giriniz</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lütfen şifreyi giriniz</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Hatalı eposta ya da şifre</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>Çok sık giriş yapılıyor, lütfen bir dakika bekleyin</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>İç Sunucu Hatası</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Giriş yapılamadı: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Giriş yapılamadı</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>logo</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>Sunucu:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>Örneğin: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>or http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Şifre:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>durum metini</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>Bilgisayar Adı:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>örnek: Can'ın bilgisayarı</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Giriş</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal et</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>Çıkış yaptınız. Lütfen</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>giriş yap</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>Hesap ekle</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Yenile</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>senkronize</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>dosyaları indeksliyor</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>senkronizasyon başlatılıyor</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>indiriyor</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>yüklüyor</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>senkronizasyon birleştirme</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>senkronizasyon için bekliyor</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>sunucu bağlı deği</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>sunucu kimliği doğrulanıyor</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>oto senkronizasyon kapatıldı</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>bilinmeyen</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Bilinmeyen hata</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>Depolama kotası tükendi</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>başlatılıyor...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>sunucuya bağlanıyor...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>dosyalar indeksleniyor...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Dosya oluşturuyor...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Dosya değişikliklerini birleştiriyor...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>İptal ediyor</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>İptal edildi</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL Hatası</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Ağ Hatası: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Sunucu Hatası</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>Veritabanı sertifikası açılamadı</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation> "%2"'de dosya "%1" mevcut değil</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 %2 dosyasını açmak için uygulama bulamadı.</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>"%1" kütüphanesini oluştur.</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>"%1" silinmiş kütüphane</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>%1'i Yeniden adlandır </translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>"%1" öğesi indirilemedi</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>kopyalama başarısız</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>Eklendi</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>Silindi</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>Kaldırıldı</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>Değiştirildi</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>Yeniden adlandırıldı</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>Eklendi ya da değiştirildi</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>Taşındı</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>Eklenen dizin</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>Kaldırılan dizin</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>Yeniden adlandırılan dizin</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>Taşınan dizin</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>dosyalar</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>dizinler</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>ve %1 tane daha</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>Şu duruma geri çevrilmiş kütüphane</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>%2 durumuna çevrilmiş "%1" dosyası</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>Kurtarılan silinmiş kütüphane</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>Değiştirilmiş kütüphane adı ya da açıklaması</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>Hemen şimdi</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 gün önce</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 gün önce</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 saat önce</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 saat önce</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation> 1 dakika önce</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 dakika önce</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><Not Part of Certificate></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>Bu kütüphaneyi şuraya eşitle:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>Bu klasörü şuraya eşitle:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>Klasör</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>Salt okunur Klasör</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>Doküman</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF Dokümanı</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>İmaj dosyası</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>Text Dokümanı</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>Ses Dosyası</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>Video Dosyası</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word Dokümanı</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint Dokümanı</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel Dokümanı</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Kütüphane "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Bu kütüphane henüz indirilmedi</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Hata:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>RepoSimgesi</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>RepoAdı</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>MetinEtiketi</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Sahip:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>En son Değiştirme:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>mtime</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Boyut:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Lokal Yol:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Durum:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>RepoDurumu</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>İsim:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Kapat</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Bu kütüphane henüz indirilmedi</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>Varolmayan "%2" kütüphanesinden "%1" dosyası açılamıyor</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Yeni Güncellenen</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Kütüphanelerim</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Alt Kütüphaneler</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>Senkronize Kütüphaneler</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Oto senkronizasyonu devre dışı bırak</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Oto senkronizasyonu etkinleştir</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>Göster &ayrıntılar</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Bu kütüphanenin ayrıntılarını göster</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Bu kütüphaneyi senkronize et</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Bu kütüphaneyi senkronize et</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Yeni Güncellenen</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>Eşitle &şimdi</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Bu kütüphaneyi hemen senkronize et</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&İptal et indirme</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Bu kütüphaneyi indirmeyi iptal et</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>Dosyayı &Aç </translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>lokal dosya aç</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Senkronizasyonu sonlandır</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>Bu kütüphane senkronizasyonunu sonlandır</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Görüntüle Bulutta</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>bu kütüphaneyi seahub'da görüntüle</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>&Aç bulut dosya tarayıcısı</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>bu kütüphaneyi Bulut Dosya Tarayıcısına gömülü aç</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>Bu kütüphaneyi &Yeniden Senkronize Et</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>bu kütüphanenin senkronizasyonu sonlandır ve yeniden senkronize et</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>"%1" kütüphanesinin senkronizasyonu sonlandırılamadı.</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Bu görev iptal edilemedi:
+
+ %1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>İndirme iptal edildi</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation> "%1" dosyası kendi üzerine yazılamıyor</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>"%1" dosyası silinemedi</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>Dosya yüklenemedi: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>tekrar dene</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>Kütüphane bilgisi alınamadı<br/>Lütfen %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Uyarı:</b> Bu sunucunun ssl sertifikası güvenilir deği, yine de devam edilsin mi?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>Log %s başlatılamadı</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Panoya kopyala</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Bilinmeyen hata</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Oto senkronizasyonu devre dışı bırak</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Oto senkronizasyonu etkinleştir</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Çık</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Ana pencereyi göster</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Ayarlar</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>Aç &dosya %1</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>%1 dosyasını aç</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>&logs klasörünü aç</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Hakkında</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Uygulamanın Hakkında kutusunu göster</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Çevrimiçi Yardım</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>Dosya</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>Oto senkronizasyon devre dışı bırakıldı</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>Yüklüyor</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>İndiriyor</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>%1 log klasörünü aç</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>%1 online yardımı aç</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>bazı sunucular bağlı değil</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Sunucunun bağlantı durumu</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>bağlı</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>bağlı değil</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Kapat</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>Lütfen kütüphane şifresini giriniz</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>%1 kütüphanesi için şifre giriniz</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Lütfen şifreyi giriniz</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>Hatalı şifre</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Bilinmeyen hata</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal et</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Ayarlar</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>Hiç</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP Proxy</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>Socks5 Proxy</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>Dili değiştirdiniz. Uygulamak için yeniden başlatılsın mı?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Başlarken ana pencereyi gizle</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Kütüphaneler senkronize edilince bildir</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>MSOffice/Libreoffice 'deki geçici dosyaların senkronizasyonunu etkinleştir</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>İndirme hız limiti </translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Yükleme hız limiti (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>Temel</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>Bir kütüphaneyi senkronize etmeyi otomatik olarak durdurma</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>Bir kütüphaneyi lokal dizini kaldırıldığında ya da başka bir nedenle erişilmez olduğunda senkronize etmeyi otomatik olarak durdurma</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>Bir kütüphaneyi sunucuda bulunmadığında senkronize etmeyi durdurma</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>Bir kütüphane sunucuda bulunmadığında senkronize etmeyi otomatik olarak sonlandırma.</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>FinderSync uzantısını etkinleştir</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>Explorer uzantısını etkinleştir</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>HTTPS senkronizasyonunda sunucu sertifası doğrulamayın</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>Başka bir isimli mevcut bir dosya ile eşitlemeyi etkinleştir</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>Gelişmiş</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>Dil (yeniden başlatma gerekir)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>Dil</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>Proxy Çeşidi:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>Host:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>Port:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>Kullanıcı adı:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Şifre:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>Proxy suucu şifre gerektirir</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>Ağ</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>İptal et</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>Bağlantı Paylaş</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>Bağlantı paylaş:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>Doğrudan İndirme</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>Panoya kopyala</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>Tamam</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Güvenilmeyen Bağlantı</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 geçersiz bir güvenlik sertifikası kullanıyor. Bağlantı güvenilir olmayabilir. Devam etmek istiyor musunuz?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>Mevcut RSA anahtar parmakizi %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>Önceki RSA anahtar parmakizi %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Seçimimi hatırla</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Evet</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Hayır</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>&Aç</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>Bu dosyayı aç</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>Web'de &Görüntüle</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>bu dosyayı websitesinde görüntüle</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>tekrar dene</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>Yıldızlı dosyaların bilgileri alınamadı<br/>Lütfen %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>Henüz yıldızlı dosyanız yok</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>%1'i kaldır</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>%1 hesabının bilgilerini kaldırmak istiyor musunuz?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Hesap bilgileri kaldırılıyor...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Dialog</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>metin</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Evet</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Hayır</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="uk" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>Не вдалося відкрити базу даних облікових записів</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>email</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>server</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>Завдання завантаження</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>видалити всі успішні завдання</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>Зараз немає завдань завантаження.</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>Очистити</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрити</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>Бібліотека</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>Шлях</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>Скасувати це завдання</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>скасувати це завдання</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>Видалити це завдання</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Не вдалося скасувати це завдання:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>Не вдалося видалити цю задачу:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>Згорнути</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрити</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>поточна швидкість завантаження</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>поточна швидкість віддачі</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>Будь ласка, оберіть папку для синхронізації</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>немає підключеного серверу</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>усі сервери підключено</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>деякі сервери не підключені</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Форма</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>лого</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>згорнути</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>закрити</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>Обрати</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>чи Перетягніть каталог</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>швидкість завантаження</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>стрілка вниз</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>швидкість віддачі</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>стрілка вгору</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>Помилка при створенні конфігурації ccnet</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>не вдалося прочитати %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>Створення бібліотеки</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Будь ласка, оберіть каталог</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>Створення...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>Будь ласка, оберіть каталог для синхронізації</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Каталог %1 не існує</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>Будь ласка, введіть ім'я</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Будь ласка, введіть пароль</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>Паролі не збігаються</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Невідома помилка</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Не вдалося додати завдання завантаження:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>Шлях:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>Вибрати</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Назва:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>зашифровано</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Пароль:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>Пароль ще раз:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>статус</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Відміна</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Будь ласка, введіть пароль</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>Синхронізація бібліотеки "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>Не вдалося додати завдання завантаження:
+%1 </translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>Завантажити бібліотеку</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>обрати...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>Пароль для цієї бібліотеки</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Скасувати</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 ініціалізація</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>Будь ласка, оберіть каталог</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>Ініціалізацію не закінчено. Дійсно вийти?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>Каталог %1 не існує</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>лого</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Оберіть...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>Далі</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Скасувати</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>Перевірка Вашої бібліотеки за замовчанням...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>Створення бібліотеки за замовчанням...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>Не вдалося створити бібліотеку за замовчанням:
+
+Необхідна версія сервера 2.1 або вище для підтримки цієї функції.</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>Завантаження бібліотеки за замовчанням...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>Вашу бібліотеку за замовчанням було завантажено.
+Клікніть "Відкрити" щоб переглянути ії.</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>Помилка при завантаженні бібліотеки за замовчанням: %1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>Не вдалося скачати бібліотеку за замовчанням:
+ %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>Пропустити</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>Виконати в фоновому режимі</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>Відкрити</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>Готово</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>Скачати бібліотеку за замовчанням</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Так</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>лого</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>Додати обліковий запис</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>Вхід...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>Помилка мережі:
+ %1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>Увага:</b> SSL-сертифікат цього сервера не є надійним! Продовжувати?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>Будь ласка, введіть адресу сервера</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 адреса сервера не припустима</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>Будь ласка, введіть ім'я користувача</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>Будь ласка, введіть ім'я комп'ютера</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>Будь ласка, введіть пароль</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>Невірні email або пароль</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>Внутрішня помилка на сервері</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>Не вдалося увійти в систему з логіном: %1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>Не вдалося увійти в систему</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>лого</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>Пароль:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>текст статусу</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>Логін</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Відміна</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>Оновити</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>синхронізований</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>індексація файлів</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation> ініціалізація синхронізації</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>завантаження</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>віддача</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>синхронізувати злиття</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>очікування синхронізації</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>сервер не з'єднано</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>аутентифікація на сервері</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>автоматичну синхронізацію вимкнено</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>невідомий</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>Невідома помилка</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>Ініціалізація...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>з'єднання з сервером...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>індексація файлів...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>Створення каталогу...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>Об'єднання змін файлів...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>Готово</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>Скасування</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>Скасовано</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL Помилка</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>Помилка мережі: %1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>Помилка серверу</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>не вдалося відкрити базу даних сертифікатів</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>Бібліотека "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>Ця бібліотека ще не завантажена</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>Помилка:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>Іконка репозиторію</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>Ім'я репозиторію</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>Текстова мітка</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>Власник:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>Остання зміна:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>час</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>Розмір:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>Локальний шлях:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>Статус:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>Статус</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>Назва:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрити</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>Цю бібліотеку не було завантажено</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>Нещодавно оновлено</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>Мої бібліотеки</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>Суб-бібліотеки</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Вимкнути автосинхронізацію</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Увімкнути автосинхронізацію</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>Показати деталі цієї бібліотеки</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>&Синхронізація цієї бібліотеки</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>Синхронізація цієї бібліотеки</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>Синхронізувати цю бібліотеку негайно</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>&Відмінити завантаження</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>Відмінити завантаження цієї бібліотеки</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>&Відкрити каталог</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>відкрити локальний каталог</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>&Розсинхронізація</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>розсинхронізувати цю бібліотеку</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>&Перегляд у хмарі</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>переглянути цю бібліотеку на вебсайті</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>Не вдалося розсинхронізувати бібліотеку "%1"</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>Не вдалося скасувати це завдання:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>Завантаження було скасоване</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b> Увага: </ B> SSL-сертифікат цього сервера не є надійним, в будь-якому випадку продовжити?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>Невідома помилка</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>Вимкнути автосинхронізацію</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>Увімкнути автосинхронізацію</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>&Вихід</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>Показати головне вікно</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>Налаштування</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>&Інфо</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>Показати інформацію про програму</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>&Онлайн допомога</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>автосинхронізацію вимкнено</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>деякі сервери не підключені</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>Статус з'єднання</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>з'єднано</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>від'єднано</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>Закрити</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>Налаштування</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>Ховати головне вікно при старті</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>Повідомляти про синхронізацію бібліотек</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>Обмеження швидкості скачування (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>Обмеження швидкості завантаження (KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>0</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>Відміна</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>Ненадійне з'єднання</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>Запам'ятати мій вибір</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Так</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ні</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>Деінсталювати %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>Дійсно хочете видалити інформацю облікового запису %1 ?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>Видалення інформації облікового запису...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>Діалог</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>текст</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>Так</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>Ні</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_CN" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation>关于 %1
+</translation>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation>%1 客户端 %2</translation>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation><h5> 版本 %1 </h5></translation>
+ </message>
+ <message>
+ <source>About</source>
+ <translation>关于</translation>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation>检查更新</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>打开帐户数据库失败</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>账号验证信息已过期,请重新登录</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation>删除本地资料库同步验证信息失败:%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation>从服务器上获取资料库同步信息失败:%1</translation>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>帐户设置</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>请输入云盘网址</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 不是合法的云盘网址</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>保存帐户信息失败</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>保存修改失败: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>成功更新当前帐户设置</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>云盘网址</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>邮箱</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation>确定要删除账号 %1 吗?<br><br>这个账号会从本地删除。同步配置也会被删除。服务器上的账号不会受到影响。</translation>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>解除同步该帐号的资料库失败:%1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>点击跳转到网页版</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>企业版</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>没有帐号</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>选择</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>帐户设置</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>登录</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>删除</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>添加一个帐号</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>登出</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>没有登录</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>帐号</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>邮箱</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>服务器</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>文件活动功能仅在 %1 企业版中提供。</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>重试</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>获取文件活动信息失败,请 %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>上传成功</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>文件 "%1"
+已成功上传。</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>文件 "%1"
+无法上传。</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>权限错误</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>账号验证信息已过期</translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>文件不存在</translation>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation>该文件被 %1锁定,请稍后再试</translation>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation>上传失败:%1</translation>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>创建头像文件夹失败</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation>正在检查权限</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>下载任务</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>移除所有已完成任务</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>当前没有下载任务。</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>清除</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>关闭</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>资料库</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>路径</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>取消任务</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>取消任务</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>删除任务</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>取消任务失败:%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>删除任务失败:%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>最小化</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>关闭</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>资料库</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>星标文件</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>文件活动</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>搜索</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>当前下载速率</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>当前上传速率</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>请选择一个文件夹来同步</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>服务器连接失败</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>所有服务器已连接</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>一些服务器未连接</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>Form</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>标志</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>最小化</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>关闭</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>...</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>选择文件夹</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation>brand</translation>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>或拖拽到这里进行同步</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>下载速率</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>向下的箭头</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>上传速率</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>向上的箭头</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>创建 ccnet 配置时出错</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>无法创建预配置文件夹 "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>读取文件 %1 失败</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>创建新资料库</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>请选择一个文件夹</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>正在创建...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation>生成资料库密钥时出错</translation>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>请选择要同步的文件夹</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>文件夹 %1 不存在</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>请输入资料库名称</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>请输入资料库密码</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>密码不一致</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>未知错误</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>添加下载任务失败:%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>创建资料库失败:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>路径:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>选择</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>名字:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>加密</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>密码:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>确认密码:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>状态文本</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation>%1 客户端初始化时出错</translation>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation>%1意外退出</translation>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation>另一个复制或移动操作正在进行中。请等待操作完成。</translation>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>请输入密码</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>同步资料库 "%1"</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>同步此目录 “%1”</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>同步到目录:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>或者</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>和已有文件夹同步</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>创建一个新的文件夹用于同步</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>和这个已存在文件夹同步:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>请选择一个目录</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>文件夹不存在</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>请选择用于同步的目录</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>您的组织已禁用把资料库放在 %1 目录外</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>和已有文件 "%1" 冲突,请选择其他目录。</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>和已同步的资料库 "%1" 冲突,请选择其他目录。</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>文件夹 "%1" 已存在。请问您是否和它同步 (其中内容会被合并)?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>点击“否” 与一个新的文件夹同步</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>无法找到其他可用的文件夹名称</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>添加下载任务失败:%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>下载资料库信息失败:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>下载资料库</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>选择...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>该资料库的密码:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>修改详情</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>已添加的文件</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>已删除的文件</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>已修改的文件</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>已添加的文件夹</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>已删除的文件夹</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>打开(&O)</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>打开父文件夹(&P)</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>云端文件浏览器</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>后退</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>前进</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>根目录</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>上传多个文件</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>上传文件夹</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>您没有权限上传到文件这个资料库</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>创建文件夹</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation>刷新</translation>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation>%1 个条目</translation>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>文件夹名称</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>无效的文件夹名!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>文件名 "%1" 已经被使用了。</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>重试</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>获取文件信息失败<br/>请 %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation>该文件夹是空的。</translation>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>请键入需要另存为的文件名...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>无法删移文件 "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>请键入需要另存到的文件夹的路径...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>您真的想删除已存在的文件 "%1" 吗?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>文件 "%1" 没有被同步</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>文件 "%1" 已经存在。<br/>您想覆盖此文件吗?<br/><small>(选择 否 用其他文件名上传)</small> </translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation>文件不存在</translation>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>下载文件失败: %1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>请选择要上传的文件</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>请选择要上传的目录</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>重命名</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>您真的想删除这些文件吗?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>创建文件夹失败</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation>锁定文件失败</translation>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>请选择要需要上传的文件 以更新 %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>重命名失败</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>删除失败</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>共享失败</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>无法从相同的文件夹中拷贝</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation>不能把文件夹复制到它的子文件夹中</translation>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>复制失败</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>移动失败</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>创建资料库失败!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>您没有权限上传到这个目录</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>账号验证信息已过期</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>权限错误</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>资料库/文件夹没有发现</translation>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation>上传文件失败 %1: %2</translation>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation>不能创建缓存目录</translation>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation>不能打开缓存目录</translation>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation>搜索文件</translation>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation>获取链接失败</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation>无法获取文件 "%1" 的上传链接</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation>请稍候</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>上传</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>正在上传 %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>下载</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>正在下载 %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%2 的 %1</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation>文件 “%1” 上传失败,您想要重试吗?</translation>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation>重试</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>跳过</translation>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation>中止</translation>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation>保存中</translation>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation>文件保存失败</translation>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation>索引处理请求错误 %1</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation>文件名</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>大小</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>修改时间</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>打开所在文件夹(&S)</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>打开所在文件夹</translation>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>操作被取消</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>请稍后</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation>任务被取消</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>服务器内部错误</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>该用户的空间已经用完</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation>被 %1 锁定</translation>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>文件名</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>大小</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>修改时间</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation>修改者</translation>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>另存为...(&S)</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation>锁定(&L)</translation>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>重命名(&R)</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>删除 (&D)</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation>共享给群组</translation>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>更新 (&U)</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>复制 (&C)</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>剪切 (&T)</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>粘贴 (&P)</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>取消下载(&C)</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>同步该目录(&S)</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>此功能只在企业版中提供</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation>获取%1下载链接</translation>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation>共享给其他用户</translation>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation>获取%1内部链接(&E)</translation>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>另存至...(&S)</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation>解除锁定(&l)</translation>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>无法删移只读文件</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>无法剪切只读文件</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation>重试上传</translation>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation>删除本地版本</translation>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation>本地版本另存为...</translation>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation>打开本地缓存目录</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation>&获取 %1 上传链接</translation>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation>获取链接失败</translation>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation>文件 "%1" 被 %2 锁定</translation>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation>获取文件 "%1" 的锁定信息失败</translation>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation>获取文件 "%1" 的上传链接失败</translation>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>创建文件夹失败</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>创建临时文件失败</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>写文件失败</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>移动旧文件时出错</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>移动文件时出错</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 初始化</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation>选择 %1 文件夹</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>请选择一个文件夹</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>初始化未完成,确认退出?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>文件夹 %1 不存在</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>标志</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation>选择一个文件夹</translation>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation>请选择一个文件夹。我们会在这个文件夹下创建 %1 目录,您下载的资料库将默认保存在此处。</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>选择...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>下一步</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1用资料库的方式来组织文件。
+您想要下载您的默认资料库吗?</translation>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>正在获取默认资料库信息...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>正在创建默认资料库...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>创建默认资料库失败:
+服务器版本必须是 2.1 以上才支持默认资料库功能。</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>获取默认资料库失败:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>创建默认资料库失败:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>正在下载默认资料库...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>下载默认资料库失败:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>默认资料库已下载。
+您可以点击“打开”按钮来查看它。</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>下载默认资料库时出错:%1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>下载资料库 “%1” 失败</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation>%1用资料库的方式来组织文件。
+您想要下载您的默认资料库吗?</translation>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>跳过</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>后台运行</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>打开</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>完成</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>下载默认资料库</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>是</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>标志</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation>加载更多</translation>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation>上传日志文件失败</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>上传日志文件</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation>权限错误!</translation>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation>资料库/文件夹没有发现</translation>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation>账号验证信息已过期</translation>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation>上传日志文件失败 :%1</translation>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation>上传日志文件成功</translation>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation>压缩中</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>%1 的 %2</translation>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>添加帐号</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation>单点登录或微信登录</translation>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>重新登录</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>登录中...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>网络错误:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>警告:</b> 该服务器的SSL 证书不可信,是否继续?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>请输入云盘网址</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 不是合法的云盘网址</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>请输入邮箱</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>请填写计算机名</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation>%1 云盘网址</translation>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation>服务器地址不能为空</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation>%1 不是合法的服务器地址。地址必须以 "https://" 开头</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>请输入密码</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>错误的邮箱或密码</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>登录过于频繁,请稍后再试</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>服务器内部错误</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>登录失败:%1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>登录失败</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>标志</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>云盘网址:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>例如: https://seacloud.cc</p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>或者 http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>密码:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>状态文本</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>计算机名:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation>邮箱 / 用户名:</translation>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>例如:小王的工作笔记本</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>登录</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation>自动登录</translation>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>您已登出。请</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>登录</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>添加一个帐号</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>刷新</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation>“%1”已同步</translation>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation>文件已经上传到 "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation>同步文件 %1 出错
+文件被其他应用锁定。这个文件将在该应用退出时更新。</translation>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation>同步文件夹 %1 出错
+该文件夹中的某个文件被其他应用锁定。这个文件夹将在该应用退出时更新。</translation>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation>同步文件 %1 出错
+该文件被其他用户锁定,因此对它作的修改不会被上传。</translation>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation>读取 %1 内容出错
+请检查文件权限以及磁盘可用空间。</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation>同步文件 %1 出错
+该文件路径包含空格或点号,因此无法在 windows 上创建</translation>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation>同步文件 %1 出错
+该文件路径包含非法字符,因此它不会被同步到这台计算机。</translation>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation>文件夹权限设置导致文件 %1 无法被更新</translation>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation>路径 %1 设置了不可同步的共享权限</translation>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation>只读仓库 %1 的更新不会被上传。</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation>对文件的并发更新。文件 %1 被保存为冲突文件</translation>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation>文件夹 %1 被移动到 seafile-recycle-bin 文件夹,因为它包含未上传的文件。</translation>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation>资料库 %1 的文件夹被移动或者删除。这个资料库未同步。</translation>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation>共享 %1</translation>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation>输入群组名称</translation>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation>输入用户名或邮件地址</translation>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation>操作成功</translation>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation>共享操作失败: %1</translation>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation>删除共享成功</translation>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation>获取文件夹共享信息时出错</translation>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation>获取群组和联系人信息时出错</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>请输入用户名</translation>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation>请输入群组名</translation>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation>“%1” 群组不存在</translation>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation>已经共享给 “%1” 群组了</translation>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation>已经共享给用户 %1 了</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>上一个操作还未完成</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation>共享给:</translation>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation>共享</translation>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation>权限:</translation>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation>可读写</translation>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation>只读</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>关闭</translation>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>已同步</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>索引文件</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>初始化</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>下载中</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>上传中</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>合并更改</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>等待同步</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>服务器未连接</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>服务器验证中</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>自动同步已关闭</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>未知</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>未知错误</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation>网络错误</translation>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation>无法解析代理服务器地址</translation>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation>无法解析服务器地址</translation>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation>无法建立到服务器的连接</translation>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation>建立安全连接时出错。请检查服务器 SSL 证书</translation>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation>数据传输被中断。请检查网络或防火墙设置</translation>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation>数据传输超时。请检查网络或防火墙设置</translation>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation>不能处理服务器的 HTTP 重定向。请检查服务器配置</translation>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation>服务器内部错误</translation>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation>计算机内存不够</translation>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation>本地文件写入出错。请检查文件权限以及磁盘可用空间。</translation>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation>用户存储空间已用完</translation>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation>资料库在服务器上被删除</translation>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation>该资料库在服务器上已损坏</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>该用户的空间已经用完</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>初始化...</translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>连接服务器...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>索引文件...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation>下载文件列表中 ...</translation>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation>下载文件中 ...</translation>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>创建文件夹...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>合并文件更改...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>完成</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation>连接服务器...</translation>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>取消中</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>已取消</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL 错误</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>网络错误:%1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>服务器内部错误</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>打开证书数据库时失败</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>文件 "%1" 不存在于路径 "%2" 中</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 找不到合适的程序来打开文件 %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>创建了资料库 "%1"</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>删除了资料库 "%1"</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>将 %1 重命名为</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>无法下载 "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>复制文件失败</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>添加了</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>删除了</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>删除了</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>修改了</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>重命名了</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation>添加或修改了</translation>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>移动了</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>添加了文件夹</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>删除了文件夹</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>重命名了文件夹</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>移动了文件夹</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>文件</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>文件夹</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>及其他 %1 个</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>资料库状态恢复到</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>文件 "%1" 状态恢复到 %2。</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>恢复了删除的文件夹</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>更改了资料库的名字或描述</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation>系统自动合并更改</translation>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>刚才</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>1 天前</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 天前</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>1 小时前</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 小时前</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>1 分钟前</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 分钟前</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><不包含这部分信息></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>同步此资料库于:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>同步此文件夹于:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>文件夹</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>只读文件夹</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>文档</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF 文档</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>图片</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>文本文件</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>音乐文件</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>视频文件</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word文档</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint文档</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel文档</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation>路径 "%1" 与系统路径冲突</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation>路径 "%1" 与已有资料库冲突</translation>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation>上传文件列表</translation>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation>文件已经被其他应用程序锁定</translation>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation>文件夹已经被其他应用程序锁定</translation>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation>文件已经被其他用户锁定</translation>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation>文件路径非法</translation>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation>索引文件时出错</translation>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation>文件路径以空格或点号结尾</translation>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation>文件路径中包含类似 "|" 和 ":" 的非法字符</translation>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation>打开文件缓存数据库失败</translation>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation>资料库名称包含非法字符例如":","*","|","?"</translation>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation>文件夹权限设置导致文件无法被更新</translation>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation>%1 已经在运行中</translation>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation>客户端数据损坏。请尝试重新同步该资料库</translation>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation>对该库没有写权限</translation>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation>没有权限同步此文件夹</translation>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation>删除了回收站中的所有条目</translation>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation>删除了回收站中 %1 天前的条目</translation>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation>发布草稿</translation>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation>创建草稿</translation>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation>创建文件</translation>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation>重命名文件</translation>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation>删除草稿</translation>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation>删除文件</translation>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation>恢复文件</translation>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation>移动文件</translation>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation>更新文件</translation>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation>创建文件夹</translation>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation>重命名文件夹</translation>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation>删除文件夹</translation>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation>恢复文件夹</translation>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation>移动文件夹</translation>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation>创建了资料库</translation>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation>重命名资料库</translation>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation>删除了资料库</translation>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation>恢复资料库</translation>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation>在不可写的资料库或者文件夹创建或更新一个文件</translation>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation>服务器权限拒绝</translation>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation>并发更新文件。文件被保存为冲突文件</translation>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation>一个文件夹中包含未上传的文件,文件夹被移动到 seafile-recycle-bin 文件夹。</translation>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation>获取同步错误标识数据库失败</translation>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation>文件不存在</translation>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>资料库 "%1"</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>这个资料库还没有下载到本地</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>错误: </translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation>%1 秒</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>资料库图标</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>资料库名字</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>文本</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>所有者:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>更新时间:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>修改时间</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>大小:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>本地路径:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>状态:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>资料库状态</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>名字:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation>同步间隔:</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>关闭</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>这个资料库还没有下载</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>无法打开不存在的资料库 "%2" 中的文件 "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>最近修改</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>我的资料库</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>子资料库</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation>共享给我的</translation>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation>公共</translation>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation>群组共享</translation>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>已同步资料库</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>初始化</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>关闭自动同步</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>打开自动同步</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>详情(&D)</translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>查看该资料库详细信息</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>同步该资料库(&S)</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>同步这个资料库</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>最近修改</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>立即同步(&S)</translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>立即同步资料库</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>取消下载(&C)</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>取消下载这个资料库</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>打开文件夹(&O)</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>打开本地文件夹</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation>打开本地文件夹(&O)</translation>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>解除同步(&U)</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>解除同步这个资料库</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>到网站上查看(&V)</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>到网站上查看这个资料库</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation>共享给其他用户</translation>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation>把这个资料库共享给其他用户</translation>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation>共享给群组</translation>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation>把这个资料库共享给某个群组</translation>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>打开云端文件浏览器(&O)</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>用内嵌的云端文件浏览器,打开此资料库</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation>退出共享(&L)</translation>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation>退出共享</translation>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>重新同步此资料库 (&R)</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>解除同步这个资料库 然后重新同步</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation>设置同步间隔 (&I)</translation>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation>设置资料库 “%1” 的同步间隔</translation>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation>您确定要解除同步资料库 "%1" 吗?</translation>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation>您确定要解除同步资料库 "%1" 吗?</translation>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation>您真的想覆盖文件 "%1" 吗?</translation>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>解除同步资料库 "%1" 失败</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation>您真的想退出共享 "%1" 吗?</translation>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation>退出共享失败</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>取消任务失败:%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>下载已取消</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation>您没有权限上传文件到这个文件夹</translation>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>无法用文件 "%1" 覆盖自身</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>无法删移文件 "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>上传文件失败: %1</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation>同步间隔 (秒)</translation>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation>设置资料库 “%1” 的同步间隔</translation>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation>搜索资料库</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>重试</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>获取资料库信息失败<br/>请 %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>警告:</b> 该服务器的SSL 证书不可信,是否继续?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>初始化日志失败: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>是</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>否</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation>保存客户端 ID 失败</translation>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation>访问 %1 失败</translation>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation>错误的客户端 ID</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>读取文件 %1 失败</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation>%1 内部链接</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>复制至剪贴板</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation>%1 内部链接</translation>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation>%1 桌面访问链接</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>未知错误</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation>内部错误:连接 daemon 失败</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>关闭自动同步</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>打开自动同步</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>退出(&Q)</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>显示主窗口</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>设置</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>打开 %1 文件夹(&F)</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>打开 %1 文件夹</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>打开日志文件夹(&L)</translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation>查看文件同步错误</translation>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>关于(&A)</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>显示关于对话框</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>在线帮助(&O)</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>文件</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>自动同步已关闭</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>正在上传</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>正在下载</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>打开 %1 日志文件夹</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>打开 %1 在线帮助文档</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>一些服务器未连接</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation>上传日志文件</translation>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation>上传 %1 日志文件</translation>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation>请先登录</translation>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation>修复文件管理器扩展</translation>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation>修复文件管理器扩展成功</translation>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation>修复文件管理器扩展失败</translation>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation>存在一些同步错误</translation>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation>打开所在文件夹(&S)</translation>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation>打开所在文件夹</translation>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation>搜索文件</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>重试</translation>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation>搜索失败<br/>请 %1</translation>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>服务器连接状态</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>已连接</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>未连接</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>关闭</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>请输入资料库密码</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>请输入资料库 %1 的密码</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>请输入密码</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>错误的密码</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>未知错误</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>设置</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation>开机自动启动 %1</translation>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation>不要在 dock 中显示 %1 图标</translation>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>没有代理</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP 代理</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>SOCKS5 代理</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation>系统代理</translation>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>您已经更改了语言。现在重启来生效吗?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation>代理服务器名不能为空</translation>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation>代理端口不正确</translation>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation>代理用户名不能为空</translation>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation>代理用户密码不能为空</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>启动时隐藏主窗口</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>资料库同步后用气泡通知</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>允许同步 office 临时文件</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>最大下载速度 (kB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>最大上传速度 (kB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>基本</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>不自动解除资料库同步</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>当资料库的本地文件夹被移除或无法访问时不自动解除同步。</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>当在服务器找不到某个资料库的信息时不要自动解除同步</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>当在服务器找不到某个资料库的信息时不要自动解除同步</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>启用 Finder 的扩展</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>启用文件浏览器的扩展</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation>自动检查更新</translation>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>HTTPS 同步过程中不验证服务器证书</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>启用与已存在的其他文件夹同步的选项</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>高级</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>语言 (需要重启)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>语言</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>代理类型:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>主机:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>端口:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>用户名:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>密码:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>代理服务器需要密码</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>网络</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation>可读写</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>只读</translation>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation>删除共享</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation>点击开始编辑</translation>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation>由 %1 创建</translation>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation>可读写</translation>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation>只读</translation>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation>群组</translation>
+ </message>
+ <message>
+ <source>User</source>
+ <translation>用户</translation>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation>权限</translation>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation>上一个操作还未完成</translation>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>共享链接</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>共享链接:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>直接下载</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>复制至剪贴板</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确认</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation>上传链接</translation>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation>上传链接:</translation>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>不安全的连接</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 使用了不合法的安全证书,该网络连接可能不安全。是否继续?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>当前 RSA 密钥指纹是 %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>过去的 RSA 密钥指纹是 %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>记住我的选择</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>是</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>否</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>打开(&O)</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>打开这个文件</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>在网站上查看(&W)</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>在网站上查看这个文件</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>重试</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>获取星标文件信息失败。<br/>请 %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>您还没有星标文件。</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation>文件同步错误</translation>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation>没有同步错误</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation>双击打开资料库</translation>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation>资料库</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>路径</translation>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation>错误</translation>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation>时间</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation>删除文件同步错误失败</translation>
+ </message>
+ <message>
+ <source>delete</source>
+ <translation>删除</translation>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation>请输入两步验证的动态口令</translation>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation>两步验证</translation>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation>请输入两步验证的动态口令</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation>mText</translation>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation>记住该设备</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>确定</translation>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>卸载 %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>是否删除 %1 帐号信息?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>删除帐户信息...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>对话框</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>text</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>是</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>否</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE TS><TS language="zh_TW" version="2.1">
+<context>
+ <name>AboutDialog</name>
+ <message>
+ <source>About %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h2>%1 Client %2</h2></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source><h5> REV %1 </h5></source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>About</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Check For Updates</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountManager</name>
+ <message>
+ <source>failed to open account database</source>
+ <translation>無法開啟帳號數據庫</translation>
+ </message>
+ <message>
+ <source>Authorization expired, please re-login</source>
+ <translation>帳號驗證訊息已過期,請重新登入</translation>
+ </message>
+ <message>
+ <source>Failed to remove local repos sync token: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get repo sync information from server: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AccountSettingsDialog</name>
+ <message>
+ <source>Account Settings</source>
+ <translation>帳號設定</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>請輸入伺服器位置</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 不是有效的伺服器位置</translation>
+ </message>
+ <message>
+ <source>Failed to save account information</source>
+ <translation>無法存儲帳號訊息</translation>
+ </message>
+ <message>
+ <source>Failed to save the changes: %1</source>
+ <translation>無法儲存以下更改: %1</translation>
+ </message>
+ <message>
+ <source>Successfully updated current account information</source>
+ <translation>成功更新目前帳號訊息</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>Server Address</source>
+ <translation>伺服器位置</translation>
+ </message>
+ <message>
+ <source>Email</source>
+ <translation>電子郵件</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>確認</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>AccountView</name>
+ <message>
+ <source>Are you sure you want to remove account %1?<br><br>The account will be removed locally. All syncing configuration will be removed too. The account at the server will not be affected.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync libraries of this account: %1</source>
+ <translation>無法解除同步此帳號下的資料庫 %1</translation>
+ </message>
+ <message>
+ <source>click to open the website</source>
+ <translation>開啟檢視網頁端</translation>
+ </message>
+ <message>
+ <source>pro version</source>
+ <translation>專業版</translation>
+ </message>
+ <message>
+ <source>No account</source>
+ <translation>沒有可用帳號</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>選擇</translation>
+ </message>
+ <message>
+ <source>Account settings</source>
+ <translation>帳號設定</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>登入</translation>
+ </message>
+ <message>
+ <source>Delete</source>
+ <translation>刪除</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>增加新的帳號</translation>
+ </message>
+ <message>
+ <source>Logout</source>
+ <translation>登出</translation>
+ </message>
+ <message>
+ <source>not logged in</source>
+ <translation>尚未登陸</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>表單</translation>
+ </message>
+ <message>
+ <source>Account</source>
+ <translation>帳號</translation>
+ </message>
+ <message>
+ <source>email</source>
+ <translation>電子郵件</translation>
+ </message>
+ <message>
+ <source>server</source>
+ <translation>伺服器</translation>
+ </message>
+</context>
+<context>
+ <name>ActivitiesTab</name>
+ <message>
+ <source>File Activities are only supported in %1 Server Professional Edition.</source>
+ <translation>很抱歉,但是此功能只在 %1 專業版本提供支援</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>重新嘗試</translation>
+ </message>
+ <message>
+ <source>Failed to get actvities information. Please %1</source>
+ <translation>無法獲取變動資訊,請 %1</translation>
+ </message>
+</context>
+<context>
+ <name>AutoUpdateManager</name>
+ <message>
+ <source>Upload Success</source>
+ <translation>上傳成功</translation>
+ </message>
+ <message>
+ <source>File "%1"
+uploaded successfully.</source>
+ <translation>檔案 "%1"
+成功上傳。</translation>
+ </message>
+ <message>
+ <source>File "%1"
+failed to upload.</source>
+ <translation>檔案 "%1"
+無法上傳。</translation>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The file is locked by %1, please try again later</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload Failure: %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>AvatarService</name>
+ <message>
+ <source>Failed to create avatars folder</source>
+ <translation>無法建立大頭照資料夾</translation>
+ </message>
+</context>
+<context>
+ <name>CheckRepoRootDirPermDialog</name>
+ <message>
+ <source>Checking Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>CloneTasksDialog</name>
+ <message>
+ <source>Download tasks</source>
+ <translation>下載任務</translation>
+ </message>
+ <message>
+ <source>remove all successful tasks</source>
+ <translation>刪除所有已完成的任務</translation>
+ </message>
+ <message>
+ <source>No download tasks right now.</source>
+ <translation>目前沒有下載任務</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>Clear</source>
+ <translation>清除</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>關閉</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableModel</name>
+ <message>
+ <source>Library</source>
+ <translation>資料庫</translation>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation>路徑</translation>
+ </message>
+</context>
+<context>
+ <name>CloneTasksTableView</name>
+ <message>
+ <source>Cancel this task</source>
+ <translation>取消這項任務</translation>
+ </message>
+ <message>
+ <source>cancel this task</source>
+ <translation>取消這項任務</translation>
+ </message>
+ <message>
+ <source>Remove this task</source>
+ <translation>刪除這項任務</translation>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>無法取消這項任務:
+
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to remove this task:
+
+ %1</source>
+ <translation>無法刪除這項任務:
+
+%1</translation>
+ </message>
+</context>
+<context>
+ <name>CloudView</name>
+ <message>
+ <source>Minimize</source>
+ <translation>視窗最小化</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>關閉</translation>
+ </message>
+ <message>
+ <source>Libraries</source>
+ <translation>資料庫</translation>
+ </message>
+ <message>
+ <source>Starred</source>
+ <translation>標示</translation>
+ </message>
+ <message>
+ <source>Activities</source>
+ <translation>事件</translation>
+ </message>
+ <message>
+ <source>Search</source>
+ <translation>檢索</translation>
+ </message>
+ <message>
+ <source>current download rate</source>
+ <translation>目前下載速率</translation>
+ </message>
+ <message>
+ <source>current upload rate</source>
+ <translation>目前上載速率</translation>
+ </message>
+ <message>
+ <source>Please Choose a folder to sync</source>
+ <translation>請選擇空閒目錄以用於同步</translation>
+ </message>
+ <message>
+ <source>no server connected</source>
+ <translation>沒有到伺服器的連接</translation>
+ </message>
+ <message>
+ <source>all servers connected</source>
+ <translation>到伺服器的連接正常運作中</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>到伺服器的鏈路部分運作中</translation>
+ </message>
+ <message>
+ <source>Form</source>
+ <translation>表單</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>圖示</translation>
+ </message>
+ <message>
+ <source>minimize</source>
+ <translation>視窗最小化</translation>
+ </message>
+ <message>
+ <source>close</source>
+ <translation>關閉</translation>
+ </message>
+ <message>
+ <source>...</source>
+ <translation>更多</translation>
+ </message>
+ <message>
+ <source>Select</source>
+ <translation>選擇</translation>
+ </message>
+ <message>
+ <source>brand</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>or Drop Folder to Sync</source>
+ <translation>或者拖拽目錄到此處 進行同步</translation>
+ </message>
+ <message>
+ <source>download rate</source>
+ <translation>下載速率</translation>
+ </message>
+ <message>
+ <source>downarrow</source>
+ <translation>向下箭頭</translation>
+ </message>
+ <message>
+ <source>upload rate</source>
+ <translation>上傳速率</translation>
+ </message>
+ <message>
+ <source>uparrow</source>
+ <translation>向上箭頭</translation>
+ </message>
+</context>
+<context>
+ <name>Configurator</name>
+ <message>
+ <source>Error when creating ccnet configuration</source>
+ <translation>在建立ccnet設定檔案時候遭遇錯誤</translation>
+ </message>
+ <message>
+ <source>Unable to create preconfigure directory "%1"</source>
+ <translation>無法建立預配置資料夾 "%1"</translation>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation>無法讀取 %1</translation>
+ </message>
+</context>
+<context>
+ <name>CreateRepoDialog</name>
+ <message>
+ <source>Create a library</source>
+ <translation>建立新的資料庫</translation>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>請選擇空閒目錄以用於同步</translation>
+ </message>
+ <message>
+ <source>Creating...</source>
+ <translation>建立 ...</translation>
+ </message>
+ <message>
+ <source>Failed to generate encryption key for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose the directory to sync</source>
+ <translation>請選擇空閒目錄以用於同步</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>目錄 %1 不存在</translation>
+ </message>
+ <message>
+ <source>Please enter the name</source>
+ <translation>請輸入名稱</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>請輸入保護密碼</translation>
+ </message>
+ <message>
+ <source>Passwords don't match</source>
+ <translation>密碼無法匹配</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>遭遇未知錯誤</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>無法增加新的下載任務:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create library on the server:
+%1</source>
+ <translation>無法在伺服器上建立新的資料庫:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>Path:</source>
+ <translation>路徑:</translation>
+ </message>
+ <message>
+ <source>Choose</source>
+ <translation>選擇</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>名稱:</translation>
+ </message>
+ <message>
+ <source>encrypted</source>
+ <translation>已加密</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>密碼:</translation>
+ </message>
+ <message>
+ <source>Password Again:</source>
+ <translation>重複密碼:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>狀態文字</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>確認</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>DaemonManager</name>
+ <message>
+ <source>%1 client failed to initialize</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 exited unexpectedly</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DataManager</name>
+ <message>
+ <source>Another copy or move operation is in progress. Please wait until it finishes.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>DownloadRepoDialog</name>
+ <message>
+ <source>Please enter the password</source>
+ <translation>請輸入保護密碼</translation>
+ </message>
+ <message>
+ <source>Sync library "%1"</source>
+ <translation>同步資料庫 %1</translation>
+ </message>
+ <message>
+ <source>Sync folder "%1"</source>
+ <translation>同步目錄 "%1"</translation>
+ </message>
+ <message>
+ <source>Sync to folder:</source>
+ <translation>同步到資料夾:</translation>
+ </message>
+ <message>
+ <source>or</source>
+ <translation>或著</translation>
+ </message>
+ <message>
+ <source>sync with an existing folder</source>
+ <translation>於已有的資料夾同步</translation>
+ </message>
+ <message>
+ <source>create a new sync folder</source>
+ <translation>創建一個新的同步資料夾</translation>
+ </message>
+ <message>
+ <source>Sync with this existing folder:</source>
+ <translation>與這個已存在的資料夾同步:</translation>
+ </message>
+ <message>
+ <source>Please choose a folder</source>
+ <translation>請選擇一個資料夾</translation>
+ </message>
+ <message>
+ <source>The folder does not exist</source>
+ <translation>此資料夾不存在</translation>
+ </message>
+ <message>
+ <source>Please choose the folder to sync.</source>
+ <translation>請選擇一個用於同步的資料夾。</translation>
+ </message>
+ <message>
+ <source>Your organization disables putting a library outside %1 folder.</source>
+ <translation>您的組織已經屏蔽將資料庫同步於 %1 目錄外的功能。</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing file "%1", please choose a different folder.</source>
+ <translation>與已有檔案 "%1" 發生衝突,請選擇其他資料夾。</translation>
+ </message>
+ <message>
+ <source>Conflicting with existing library "%1", please choose a different folder.</source>
+ <translation>與已有的資料庫 "%1" 發生衝突,請選擇其他資料夾。</translation>
+ </message>
+ <message>
+ <source>The folder "%1" already exists. Are you sure to sync with it (contents will be merged)?</source>
+ <translation>資料夾 "%1" 已經存在。 請問您是否與之同步 (內容會被合併) ?</translation>
+ </message>
+ <message>
+ <source>Click No to sync with a new folder instead</source>
+ <translation>點擊“否” 則與一個新的資料夾同步</translation>
+ </message>
+ <message>
+ <source>Unable to find an alternative folder name</source>
+ <translation>無法找到其他合適的資料夾名稱</translation>
+ </message>
+ <message>
+ <source>Failed to add download task:
+ %1</source>
+ <translation>無法增加新的下載任務:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to get repo download information:
+%1</source>
+ <translation>無法獲取資料庫的下載檔案:
+%1</translation>
+ </message>
+ <message>
+ <source>Download Library</source>
+ <translation>下載資料庫</translation>
+ </message>
+ <message>
+ <source>choose...</source>
+ <translation>選取...</translation>
+ </message>
+ <message>
+ <source>Password for this library:</source>
+ <translation>此資料庫的密碼:</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>確認</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsDialog</name>
+ <message>
+ <source>Modification Details</source>
+ <translation>詳細的修改差異集</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListModel</name>
+ <message>
+ <source>Added files</source>
+ <translation>已添加的檔案</translation>
+ </message>
+ <message>
+ <source>Deleted files</source>
+ <translation>已刪除的檔案</translation>
+ </message>
+ <message>
+ <source>Modified files</source>
+ <translation>已修改的檔案</translation>
+ </message>
+ <message>
+ <source>Added folders</source>
+ <translation>已添加的資料夾</translation>
+ </message>
+ <message>
+ <source>Deleted folders</source>
+ <translation>已刪除的資料夾</translation>
+ </message>
+</context>
+<context>
+ <name>EventDetailsListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>打開(&O)
+</translation>
+ </message>
+ <message>
+ <source>Open &parent folder</source>
+ <translation>打開父資料夾(&P)</translation>
+ </message>
+</context>
+<context>
+ <name>FileBrowserDialog</name>
+ <message>
+ <source>Cloud File Browser</source>
+ <translation>雲端檔案瀏覽器</translation>
+ </message>
+ <message>
+ <source>Back</source>
+ <translation>回退</translation>
+ </message>
+ <message>
+ <source>Forward</source>
+ <translation>前進</translation>
+ </message>
+ <message>
+ <source>Home</source>
+ <translation>根目錄</translation>
+ </message>
+ <message>
+ <source>Upload files</source>
+ <translation>上傳多個檔案</translation>
+ </message>
+ <message>
+ <source>Upload a directory</source>
+ <translation>上傳目錄</translation>
+ </message>
+ <message>
+ <source>You don't have permission to upload files to this library</source>
+ <translation>您沒有權限上傳檔案到這個資料庫</translation>
+ </message>
+ <message>
+ <source>Create a folder</source>
+ <translation>新建目錄</translation>
+ </message>
+ <message>
+ <source>Refresh</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 items</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder name</source>
+ <translation>資料夾名稱</translation>
+ </message>
+ <message>
+ <source>Invalid folder name!</source>
+ <translation>無效的目錄名稱!</translation>
+ </message>
+ <message>
+ <source>The name "%1" is already taken.</source>
+ <translation>名稱 "%1" 已經被佔用了。</translation>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>重新嘗試</translation>
+ </message>
+ <message>
+ <source>Failed to get files information<br/>Please %1</source>
+ <translation>無法獲取檔案訊息<br/>
+請 %1</translation>
+ </message>
+ <message>
+ <source>This folder is empty.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter name of file to save to...</source>
+ <translation>請輸入需要另存為的檔案名稱...</translation>
+ </message>
+ <message>
+ <source>Unable to remove file "%1"</source>
+ <translation>無法刪除檔案 "%1"</translation>
+ </message>
+ <message>
+ <source>Enter the path of the folder you want to save to...</source>
+ <translation>請輸入需要另存到的資料檔的路徑...</translation>
+ </message>
+ <message>
+ <source>Do you want to overwrite the existing file "%1"?</source>
+ <translation>您真的想刪除已有檔案 "%1" 嗎?</translation>
+ </message>
+ <message>
+ <source>File "%1" haven't been synced</source>
+ <translation>檔案 "%1" 沒有被同步</translation>
+ </message>
+ <message>
+ <source>File %1 already exists.<br/>Do you like to overwrite it?<br/><small>(Choose No to upload using an alternative name).</small></source>
+ <translation>檔案 %1 已經存在。<br/>您想覆蓋它嗎?<br/><small>(選 否 會使用不同的名字)。</small></translation>
+ </message>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to download file: %1</source>
+ <translation>無法下載檔案:%1</translation>
+ </message>
+ <message>
+ <source>Select a file to upload</source>
+ <translation>請選擇需要上傳的檔案</translation>
+ </message>
+ <message>
+ <source>Select a directory to upload</source>
+ <translation>選擇你需要上傳的目錄</translation>
+ </message>
+ <message>
+ <source>Rename</source>
+ <translation>重命名</translation>
+ </message>
+ <message>
+ <source>Do you really want to delete these items</source>
+ <translation>您真的想刪除這些檔案嗎?</translation>
+ </message>
+ <message>
+ <source>Create folder failed</source>
+ <translation>建立目錄失敗</translation>
+ </message>
+ <message>
+ <source>Lock file failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Select a file to update %1</source>
+ <translation>請選擇需要上傳的檔案 以更新 %1</translation>
+ </message>
+ <message>
+ <source>Rename failed</source>
+ <translation>重命名失敗</translation>
+ </message>
+ <message>
+ <source>Remove failed</source>
+ <translation>刪除失敗</translation>
+ </message>
+ <message>
+ <source>Share failed</source>
+ <translation>分享失敗</translation>
+ </message>
+ <message>
+ <source>Cannot paste files from the same folder</source>
+ <translation>無法從相同的目錄拷貝檔案</translation>
+ </message>
+ <message>
+ <source>Cannot paste the folder to its subfolder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy failed</source>
+ <translation>複製失敗</translation>
+ </message>
+ <message>
+ <source>Move failed</source>
+ <translation>移動失敗</translation>
+ </message>
+ <message>
+ <source>Create library failed!</source>
+ <translation>建立目錄失敗!</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to upload file %1: %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to create cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to open cache folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserProgressDialog</name>
+ <message>
+ <source>Pending</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <source>Upload</source>
+ <translation>上傳</translation>
+ </message>
+ <message>
+ <source>Uploading %1</source>
+ <translation>正在上傳 %1</translation>
+ </message>
+ <message>
+ <source>Download</source>
+ <translation>下載</translation>
+ </message>
+ <message>
+ <source>Downloading %1</source>
+ <translation>正在下載 %1</translation>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation>已完成 %2 中的 %1</translation>
+ </message>
+ <message>
+ <source>Failed to upload file "%1", do you want to retry?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Abort</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Saving</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File save failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Index progress request error %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchModel</name>
+ <message>
+ <source>Name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileBrowserSearchView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileNetworkTask</name>
+ <message>
+ <source>Operation canceled</source>
+ <translation>操作已取消</translation>
+ </message>
+ <message>
+ <source>pending</source>
+ <translation>等待中</translation>
+ </message>
+</context>
+<context>
+ <name>FileServerTask</name>
+ <message>
+ <source>task cancelled</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>內部伺服器錯誤</translation>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableModel</name>
+ <message>
+ <source>locked by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Name</source>
+ <translation>名稱</translation>
+ </message>
+ <message>
+ <source>Size</source>
+ <translation>檔案大小</translation>
+ </message>
+ <message>
+ <source>Last Modified</source>
+ <translation>最後修改日期</translation>
+ </message>
+ <message>
+ <source>Modifier</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FileTableView</name>
+ <message>
+ <source>&Save As...</source>
+ <translation>另存為... (&S)</translation>
+ </message>
+ <message>
+ <source>&Lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Rename</source>
+ <translation>重命名(&R)</translation>
+ </message>
+ <message>
+ <source>&Delete</source>
+ <translation>刪除(&D)</translation>
+ </message>
+ <message>
+ <source>Share to Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Update</source>
+ <translation>更新(&U)</translation>
+ </message>
+ <message>
+ <source>&Copy</source>
+ <translation>複製 (&C)</translation>
+ </message>
+ <message>
+ <source>Cu&t</source>
+ <translation>剪貼 (&T)</translation>
+ </message>
+ <message>
+ <source>&Paste</source>
+ <translation>粘貼 (&P)</translation>
+ </message>
+ <message>
+ <source>Canc&el Download</source>
+ <translation>取消下載(&C)</translation>
+ </message>
+ <message>
+ <source>&Sync this folder</source>
+ <translation>同步此資料夾 (&S)</translation>
+ </message>
+ <message>
+ <source>This feature is available in pro version only
+</source>
+ <translation>此功能只在專業版中提供</translation>
+ </message>
+ <message>
+ <source>&Generate %1 Download Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>G&enerate %1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Save As To...</source>
+ <translation>另存到... (&S)</translation>
+ </message>
+ <message>
+ <source>Un&lock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to remove readonly files</source>
+ <translation>無法刪除只讀文件</translation>
+ </message>
+ <message>
+ <source>Unable to cut readonly files</source>
+ <translation>無法剪切只讀文件</translation>
+ </message>
+ <message>
+ <source>Retry Upload</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Delete Local Version</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Local Version Save As...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Open Local Cache Folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Generate %1 Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>FinderSyncHost</name>
+ <message>
+ <source>Failed to get link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File "%1" is locked by %2</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get lock information for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get upload link for file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>GetFileTask</name>
+ <message>
+ <source>Failed to create folders</source>
+ <translation>無法建立資料夾</translation>
+ </message>
+ <message>
+ <source>Failed to create temporary files</source>
+ <translation>無法建立臨時檔案</translation>
+ </message>
+ <message>
+ <source>Failed to write file to disk</source>
+ <translation>無法將檔案寫入磁盤</translation>
+ </message>
+ <message>
+ <source>Failed to remove the older version of the downloaded file</source>
+ <translation>無法刪除已下載的檔案</translation>
+ </message>
+ <message>
+ <source>Failed to move file</source>
+ <translation>無法刪除檔案</translation>
+ </message>
+</context>
+<context>
+ <name>InitSeafileDialog</name>
+ <message>
+ <source>%1 Initialization</source>
+ <translation>%1 還在初始化</translation>
+ </message>
+ <message>
+ <source>Choose %1 folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a directory</source>
+ <translation>請選擇空閒目錄以用於同步</translation>
+ </message>
+ <message>
+ <source>Initialization is not finished. Really quit?</source>
+ <translation>初始化還沒有完成,確認現在退出?</translation>
+ </message>
+ <message>
+ <source>The folder %1 does not exist</source>
+ <translation>目錄 %1 並不存在</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>圖示</translation>
+ </message>
+ <message>
+ <source>Choose a folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>選取...</translation>
+ </message>
+ <message>
+ <source>Next</source>
+ <translation>下一步</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>InitVirtualDriveDialog</name>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Checking your default library...</source>
+ <translation>正在檢查您的默認資料庫...</translation>
+ </message>
+ <message>
+ <source>Creating the default library...</source>
+ <translation>正在建立默認資料庫...</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+
+The server version must be 2.1 or higher to support this.</source>
+ <translation>無法建立默認資料庫:
+
+此項功能只在伺服器版本2.1或者之上被支援</translation>
+ </message>
+ <message>
+ <source>Failed to get default library:
+%1</source>
+ <translation>無法取得默認資料庫:
+%1</translation>
+ </message>
+ <message>
+ <source>Failed to create default library:
+%1</source>
+ <translation>無法建立默認資料庫:
+%1</translation>
+ </message>
+ <message>
+ <source>Downloading default library...</source>
+ <translation>正在下載默認資料庫...</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+%1</source>
+ <translation>無法下載默認資料庫:
+%1</translation>
+ </message>
+ <message>
+ <source>The default library has been downloaded.
+You can click the "Open" button to view it.</source>
+ <translation>默認資料庫已下載完畢。
+您可以點擊“開啟”查看。</translation>
+ </message>
+ <message>
+ <source>Error when downloading the default library: %1</source>
+ <translation>在下載默認資料庫的時候遭遇錯誤:%1</translation>
+ </message>
+ <message>
+ <source>Failed to download default library:
+ %1</source>
+ <translation>無法下載默認資料庫:
+%1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>%1 organizes files by libraries.
+Do you like to download your default library?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Skip</source>
+ <translation>略過</translation>
+ </message>
+ <message>
+ <source>Run in Background</source>
+ <translation>後台模式運行</translation>
+ </message>
+ <message>
+ <source>Open</source>
+ <translation>開啟</translation>
+ </message>
+ <message>
+ <source>Finish</source>
+ <translation>完結</translation>
+ </message>
+ <message>
+ <source>Download Default Library</source>
+ <translation>下載默認資料庫</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>好</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>圖示</translation>
+ </message>
+</context>
+<context>
+ <name>LoadMoreButton</name>
+ <message>
+ <source>load more</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogDirUploader</name>
+ <message>
+ <source>Upload log files failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission Error!</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library/Folder not found.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Authorization expired</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload log files failed :%1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully uploaded log files</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogUploadProgressDialog</name>
+ <message>
+ <source>Compressing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 of %2</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LoginDialog</name>
+ <message>
+ <source>Add an account</source>
+ <translation>增加新的帳號</translation>
+ </message>
+ <message>
+ <source>Single Sign On</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Re-login</source>
+ <translation>重新登陸</translation>
+ </message>
+ <message>
+ <source>Logging in...</source>
+ <translation>登入中...</translation>
+ </message>
+ <message>
+ <source>Network Error:
+ %1</source>
+ <translation>網路錯誤:
+%1</translation>
+ </message>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>警告:</b> 伺服器的SSL證書不被信任,請問還需要繼續操作嗎?</translation>
+ </message>
+ <message>
+ <source>Please enter the server address</source>
+ <translation>請輸入伺服器地址</translation>
+ </message>
+ <message>
+ <source>%1 is not a valid server address</source>
+ <translation>%1 不是有效的伺服器地址</translation>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation>請輸入用戶名</translation>
+ </message>
+ <message>
+ <source>Please enter the computer name</source>
+ <translation>請輸入此計算機的代號</translation>
+ </message>
+ <message>
+ <source>%1 Server Address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server address must not be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 is not a valid server address. It has to start with 'https://'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>請輸入保護密碼</translation>
+ </message>
+ <message>
+ <source>Incorrect email or password</source>
+ <translation>無法理解的郵件地址或者密碼</translation>
+ </message>
+ <message>
+ <source>Logging in too frequently, please wait a minute</source>
+ <translation>嘗試展登入過於頻繁,請稍後嘗試</translation>
+ </message>
+ <message>
+ <source>Internal Server Error</source>
+ <translation>內部伺服器錯誤</translation>
+ </message>
+ <message>
+ <source>Failed to login: %1</source>
+ <translation>無法登入:%1</translation>
+ </message>
+ <message>
+ <source>Failed to login</source>
+ <translation>無法登入</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>logo</source>
+ <translation>圖示</translation>
+ </message>
+ <message>
+ <source>Server:</source>
+ <translation>伺服器:</translation>
+ </message>
+ <message>
+ <source><html><head/><body><p>For example: https://seacloud.cc</p></body></html></source>
+ <translation><html><head/><body><p>比如 https://seacloud.cc </p></body></html></translation>
+ </message>
+ <message>
+ <source>or http://192.168.1.24:8000</source>
+ <translation>或者 http://192.168.1.24:8000</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>密碼:</translation>
+ </message>
+ <message>
+ <source>status text</source>
+ <translation>狀態文字</translation>
+ </message>
+ <message>
+ <source>Computer Name:</source>
+ <translation>計算機代號:</translation>
+ </message>
+ <message>
+ <source>Email / Username:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>e.g. Jim's laptop</source>
+ <translation>比如 Jim 的本本</translation>
+ </message>
+ <message>
+ <source>Login</source>
+ <translation>登入</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+ <message>
+ <source>Automatic Login</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>LogoutView</name>
+ <message>
+ <source>You are logout. Please </source>
+ <translation>您已登出。請</translation>
+ </message>
+ <message>
+ <source>login</source>
+ <translation>登入</translation>
+ </message>
+ <message>
+ <source>Add an account</source>
+ <translation>增加新的帳號</translation>
+ </message>
+</context>
+<context>
+ <name>MainWindow</name>
+ <message>
+ <source>Refresh</source>
+ <translation>重新整理</translation>
+ </message>
+</context>
+<context>
+ <name>MessagePoller</name>
+ <message>
+ <source>"%1" is synchronized</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Files uploaded to "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by other application. This file will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync folder %1
+Some file in this folder is locked by other application. This folder will be updated when you close the application.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync file %1
+File is locked by another user. Update to this file is not uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to index file %1
+Please check file permission and disk space.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path is ended with space or period and cannot be created on Windows.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to sync %1
+File path contains invalid characters. It is not synced to this computer.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file %1 is denied by folder permission setting.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync folder %1.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updates in read-only library %1 will not be uploaded.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File %1 is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder for library %1 is removed or moved. The library is unsynced.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>PrivateShareDialog</name>
+ <message>
+ <source>Share %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Enter user name or email address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share Operation Failed: %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed successfully</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get share information of the folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to get your groups and contacts information</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the username</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the group name</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No such group "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to group %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Already shared to user %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share To:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read-Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>QObject</name>
+ <message>
+ <source>synchronized</source>
+ <translation>已同步</translation>
+ </message>
+ <message>
+ <source>indexing files</source>
+ <translation>正在索引檔案</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation>同步初始化完畢</translation>
+ </message>
+ <message>
+ <source>downloading</source>
+ <translation>正在下載</translation>
+ </message>
+ <message>
+ <source>uploading</source>
+ <translation>正在上傳</translation>
+ </message>
+ <message>
+ <source>sync merging</source>
+ <translation>同步合併中</translation>
+ </message>
+ <message>
+ <source>waiting for sync</source>
+ <translation>等待同步中</translation>
+ </message>
+ <message>
+ <source>server not connected</source>
+ <translation>沒有接入伺服器</translation>
+ </message>
+ <message>
+ <source>server authenticating</source>
+ <translation>正在和伺服器驗證身份</translation>
+ </message>
+ <message>
+ <source>auto sync is turned off</source>
+ <translation>自動同步已關閉</translation>
+ </message>
+ <message>
+ <source>unknown</source>
+ <translation>未知</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>遭遇未知錯誤</translation>
+ </message>
+ <message>
+ <source>Network error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve proxy address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot resolve server address</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cannot connect to server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to establish secure connection. Please check server SSL certificate</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer was interrupted. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Data transfer timed out. Please check network or firewall</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unhandled http redirect from server. Please check server cofiguration</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Server error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Not enough memory</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to write data on the client. Please check disk space or folder permissions</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Storage quota full</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library deleted on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library damaged on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The storage quota has been used up</source>
+ <translation>空間配額已用盡</translation>
+ </message>
+ <message>
+ <source>initializing...</source>
+ <translation>初始化中... </translation>
+ </message>
+ <message>
+ <source>connecting server...</source>
+ <translation>連接伺服器中...</translation>
+ </message>
+ <message>
+ <source>indexing files...</source>
+ <translation>索引檔案中...</translation>
+ </message>
+ <message>
+ <source>Downloading file list...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Downloading files...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Creating folder...</source>
+ <translation>建立資料夾中...</translation>
+ </message>
+ <message>
+ <source>Merge file changes...</source>
+ <translation>合併檔案衝突中...</translation>
+ </message>
+ <message>
+ <source>Done</source>
+ <translation>完成</translation>
+ </message>
+ <message>
+ <source>checking server info...</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Canceling</source>
+ <translation>取消中...</translation>
+ </message>
+ <message>
+ <source>Canceled</source>
+ <translation>已取消</translation>
+ </message>
+ <message>
+ <source>SSL Error</source>
+ <translation>SSL 安全證書錯誤</translation>
+ </message>
+ <message>
+ <source>Network Error: %1</source>
+ <translation>網路錯誤:%1</translation>
+ </message>
+ <message>
+ <source>Server Error</source>
+ <translation>伺服器錯誤</translation>
+ </message>
+ <message>
+ <source>failed to open certs database</source>
+ <translation>無法開啟證書數據庫</translation>
+ </message>
+ <message>
+ <source>File "%1" doesn't exist in "%2"</source>
+ <translation>檔案 "%1" 不存在於路徑 "%2" 中</translation>
+ </message>
+ <message>
+ <source>%1 couldn't find an application to open file %2</source>
+ <translation>%1 沒有能找到合適的應用程式開啟檔案 %2</translation>
+ </message>
+ <message>
+ <source>Created library "%1"</source>
+ <translation>建立新的資料庫 %1</translation>
+ </message>
+ <message>
+ <source>Deleted library "%1"</source>
+ <translation>刪除的資料庫 %1</translation>
+ </message>
+ <message>
+ <source>Rename %1 to</source>
+ <translation>將 %1 重命名為</translation>
+ </message>
+ <message>
+ <source>Unable to download item "%1"</source>
+ <translation>無法下載 "%1"</translation>
+ </message>
+ <message>
+ <source>copy failed</source>
+ <translation>複製失敗</translation>
+ </message>
+ <message>
+ <source>Added</source>
+ <translation>新增的</translation>
+ </message>
+ <message>
+ <source>Deleted</source>
+ <translation>刪除的</translation>
+ </message>
+ <message>
+ <source>Removed</source>
+ <translation>已被被刪除的</translation>
+ </message>
+ <message>
+ <source>Modified</source>
+ <translation>修改的</translation>
+ </message>
+ <message>
+ <source>Renamed</source>
+ <translation>重命名的</translation>
+ </message>
+ <message>
+ <source>Added or modified</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved</source>
+ <translation>移動的</translation>
+ </message>
+ <message>
+ <source>Added directory</source>
+ <translation>新增的資料夾</translation>
+ </message>
+ <message>
+ <source>Removed directory</source>
+ <translation>已被被刪除的資料夾</translation>
+ </message>
+ <message>
+ <source>Renamed directory</source>
+ <translation>重命名的資料夾</translation>
+ </message>
+ <message>
+ <source>Moved directory</source>
+ <translation>移動的資料夾</translation>
+ </message>
+ <message>
+ <source>files</source>
+ <translation>檔案</translation>
+ </message>
+ <message>
+ <source>directories</source>
+ <translation>目錄</translation>
+ </message>
+ <message>
+ <source>and %1 more</source>
+ <translation>還有 %1 等等</translation>
+ </message>
+ <message>
+ <source>Reverted library to status at</source>
+ <translation>恢復資料庫到狀態</translation>
+ </message>
+ <message>
+ <source>Reverted file "%1" to status at %2.</source>
+ <translation>恢復檔案 %1 到狀態 %2</translation>
+ </message>
+ <message>
+ <source>Recovered deleted directory</source>
+ <translation>恢復被刪除的資料夾</translation>
+ </message>
+ <message>
+ <source>Changed library name or description</source>
+ <translation>改變資料庫的名稱或者描述詞</translation>
+ </message>
+ <message>
+ <source>Auto merge by %1 system</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Just now</source>
+ <translation>就是現在</translation>
+ </message>
+ <message>
+ <source>1 day ago</source>
+ <translation>一天前</translation>
+ </message>
+ <message>
+ <source>%1 days ago</source>
+ <translation>%1 天前</translation>
+ </message>
+ <message>
+ <source>1 hour ago</source>
+ <translation>一小時前</translation>
+ </message>
+ <message>
+ <source>%1 hours ago</source>
+ <translation>%1 小時前</translation>
+ </message>
+ <message>
+ <source>1 minute ago</source>
+ <translation>一分鐘前</translation>
+ </message>
+ <message>
+ <source>%1 minutes ago</source>
+ <translation>%1 分鐘前</translation>
+ </message>
+ <message>
+ <source><Not Part of Certificate></source>
+ <translation><沒有包含在證書中></translation>
+ </message>
+ <message>
+ <source>Sync this library to:</source>
+ <translation>將此資料庫同步與:</translation>
+ </message>
+ <message>
+ <source>Sync this folder to:</source>
+ <translation>將此資料夾同步與:</translation>
+ </message>
+ <message>
+ <source>Folder</source>
+ <translation>資料夾</translation>
+ </message>
+ <message>
+ <source>Readonly Folder</source>
+ <translation>只讀資料夾</translation>
+ </message>
+ <message>
+ <source>Document</source>
+ <translation>檔案</translation>
+ </message>
+ <message>
+ <source>PDF Document</source>
+ <translation>PDF 檔案</translation>
+ </message>
+ <message>
+ <source>Image File</source>
+ <translation>圖像檔案</translation>
+ </message>
+ <message>
+ <source>Text Document</source>
+ <translation>文檔檔案</translation>
+ </message>
+ <message>
+ <source>Audio File</source>
+ <translation>音樂檔案</translation>
+ </message>
+ <message>
+ <source>Video File</source>
+ <translation>視頻檔案</translation>
+ </message>
+ <message>
+ <source>Word Document</source>
+ <translation>Word檔案</translation>
+ </message>
+ <message>
+ <source>PowerPoint Document</source>
+ <translation>PowerPoint檔案</translation>
+ </message>
+ <message>
+ <source>Excel Document</source>
+ <translation>Excel檔案</translation>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with system path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The path "%1" conflicts with an existing library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>uploading file list</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Folder is locked by another application</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>File is locked by another user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path is invalid</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error when indexing</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path ends with space or period character</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path contains invalid characters like '|' or ':'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open file cache database</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library name contains invalid characters such as ':', '*', '|', '?'</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Update to file denied by folder permission setting</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Client is already running</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Internal data corrupt on the client. Please try to resync the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not have write permission to the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No permission to sync this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed all items from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Removed items older than days %1 from trash</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Published draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted draft</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Updated file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Moved folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Renamed library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Deleted library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Restored library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created or updated a file in a non-writable library or folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission denied on server</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Concurrent updates to file. File is saved as conflict file</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to open sync error id database</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReliablePostFileTask</name>
+ <message>
+ <source>File does not exist</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoDetailDialog</name>
+ <message>
+ <source>Library "%1"</source>
+ <translation>資料庫 %1</translation>
+ </message>
+ <message>
+ <source>This library is not downloaded yet</source>
+ <translation>此資料庫還沒有被下載</translation>
+ </message>
+ <message>
+ <source>Error: </source>
+ <translation>錯誤:</translation>
+ </message>
+ <message>
+ <source>every %1 seconds</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>RepoIcon</source>
+ <translation>資料庫圖示</translation>
+ </message>
+ <message>
+ <source>RepoName</source>
+ <translation>資料庫名稱</translation>
+ </message>
+ <message>
+ <source>TextLabel</source>
+ <translation>文本標簽:</translation>
+ </message>
+ <message>
+ <source>Owner:</source>
+ <translation>所有者:</translation>
+ </message>
+ <message>
+ <source>Last Modified:</source>
+ <translation>最後修改日期:</translation>
+ </message>
+ <message>
+ <source>mtime</source>
+ <translation>最後修改日期</translation>
+ </message>
+ <message>
+ <source>Size:</source>
+ <translation>檔案大小:</translation>
+ </message>
+ <message>
+ <source>Local Path:</source>
+ <translation>本地路徑:</translation>
+ </message>
+ <message>
+ <source>Status:</source>
+ <translation>狀態:</translation>
+ </message>
+ <message>
+ <source>RepoStatus</source>
+ <translation>資料庫狀態:</translation>
+ </message>
+ <message>
+ <source>Name:</source>
+ <translation>名稱:</translation>
+ </message>
+ <message>
+ <source>Sync Interval:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>關閉</translation>
+ </message>
+</context>
+<context>
+ <name>RepoItemDelegate</name>
+ <message>
+ <source>, %1%2</source>
+ <translation>, %1%2</translation>
+ </message>
+ <message>
+ <source>, %1</source>
+ <translation>, %1</translation>
+ </message>
+ <message>
+ <source>This library has not been downloaded</source>
+ <translation>此資料庫還沒有被下載</translation>
+ </message>
+</context>
+<context>
+ <name>RepoService</name>
+ <message>
+ <source>Unable to open file "%1" from nonexistent library "%2"</source>
+ <translation>無法打開不存在資料庫 "%2" 中的文件 "%1"</translation>
+ </message>
+</context>
+<context>
+ <name>RepoTreeModel</name>
+ <message>
+ <source>Recently Updated</source>
+ <translation>最近更新</translation>
+ </message>
+ <message>
+ <source>My Libraries</source>
+ <translation>我的資料庫</translation>
+ </message>
+ <message>
+ <source>Sub Libraries</source>
+ <translation>子資料庫</translation>
+ </message>
+ <message>
+ <source>Shared with me</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with all</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Shared with groups</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Synced Libraries</source>
+ <translation>已同步資料庫</translation>
+ </message>
+ <message>
+ <source>sync initializing</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>RepoTreeView</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>關閉自動同步</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>開啓自動同步</translation>
+ </message>
+ <message>
+ <source>Show &details</source>
+ <translation>顯示資料 (&D) </translation>
+ </message>
+ <message>
+ <source>Show details of this library</source>
+ <translation>顯示此資料庫的檔案</translation>
+ </message>
+ <message>
+ <source>&Sync this library</source>
+ <translation>同步此資料庫 (&S)</translation>
+ </message>
+ <message>
+ <source>Sync this library</source>
+ <translation>同步此資料庫</translation>
+ </message>
+ <message>
+ <source>Recently Updated</source>
+ <translation>最近更新</translation>
+ </message>
+ <message>
+ <source>Sync &now</source>
+ <translation>立即同步 (&N) </translation>
+ </message>
+ <message>
+ <source>Sync this library immediately</source>
+ <translation>立即同步此資料庫</translation>
+ </message>
+ <message>
+ <source>&Cancel download</source>
+ <translation>取消下載(&C)</translation>
+ </message>
+ <message>
+ <source>Cancel download of this library</source>
+ <translation>取消下載此資料庫</translation>
+ </message>
+ <message>
+ <source>&Open folder</source>
+ <translation>開啟此資料夾(&O)</translation>
+ </message>
+ <message>
+ <source>open local folder</source>
+ <translation>開啟本地資料夾</translation>
+ </message>
+ <message>
+ <source>&Open local folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Unsync</source>
+ <translation>取消同步(&U)</translation>
+ </message>
+ <message>
+ <source>unsync this library</source>
+ <translation>取消同步此資料庫</translation>
+ </message>
+ <message>
+ <source>&View on cloud</source>
+ <translation>在瀏覽器中檢視(&V)</translation>
+ </message>
+ <message>
+ <source>view this library on seahub</source>
+ <translation>在瀏覽器中檢視此資料庫</translation>
+ </message>
+ <message>
+ <source>Share to user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a user</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share to group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Share this library to a group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Open cloud file browser</source>
+ <translation>開啟雲端檔案瀏覽器</translation>
+ </message>
+ <message>
+ <source>open this library in embedded Cloud File Browser</source>
+ <translation>用內置的雲端檔案瀏覽器檢視此資料庫</translation>
+ </message>
+ <message>
+ <source>&Leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>leave share</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&Resync this library</source>
+ <translation>重新同步(&R)</translation>
+ </message>
+ <message>
+ <source>unsync and resync this library</source>
+ <translation>取消同步此資料庫然後重新開啟同步</translation>
+ </message>
+ <message>
+ <source>Set sync &Interval</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>set sync interval for this library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to unsync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to resync the library "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Are you sure to overwrite the file "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to unsync library "%1"</source>
+ <translation>無法取消同步資料庫 %1</translation>
+ </message>
+ <message>
+ <source>Are you sure you want to leave the share "%1"?</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Leaving share failed</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to cancel this task:
+
+ %1</source>
+ <translation>無法取消這項任務:
+
+%1</translation>
+ </message>
+ <message>
+ <source>The download has been canceled</source>
+ <translation>下載已被取消</translation>
+ </message>
+ <message>
+ <source>You do not have permission to upload to this folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Unable to overwrite file "%1" with itself</source>
+ <translation>無法刪除用文件 "%1" 覆蓋自身</translation>
+ </message>
+ <message>
+ <source>Unable to delete file "%1"</source>
+ <translation>無法刪除檔案 "%1"</translation>
+ </message>
+ <message>
+ <source>Failed to upload file: %1</source>
+ <translation>無法上傳檔案 "%1"</translation>
+ </message>
+ <message>
+ <source>Sync Interval (In seconds):</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Set Sync Internval For Library "%1"</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ReposTab</name>
+ <message>
+ <source>Search libraries</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation>重新嘗試</translation>
+ </message>
+ <message>
+ <source>Failed to get libraries information<br/>Please %1</source>
+ <translation>無法獲取資料庫檔案 <br/>
+請 %1</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApiClient</name>
+ <message>
+ <source><b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?</source>
+ <translation><b>警告:</b> 伺服器的SSL證書不被信任,請問還需要繼續操作嗎?</translation>
+ </message>
+</context>
+<context>
+ <name>SeafileApplet</name>
+ <message>
+ <source>Failed to initialize log: %s</source>
+ <translation>無法初始化日誌: %s</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to save client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to access %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>incorrect client id</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>failed to read %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileLinkDialog</name>
+ <message>
+ <source>%1 Internal Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>複製到剪貼簿</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>確認</translation>
+ </message>
+ <message>
+ <source>%1 Internal Link:</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>%1 Desktop Access Link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileRpcClient</name>
+ <message>
+ <source>Unknown error</source>
+ <translation>遭遇未知錯誤</translation>
+ </message>
+ <message>
+ <source>internal error: failed to connect to daemon</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SeafileTrayIcon</name>
+ <message>
+ <source>Disable auto sync</source>
+ <translation>取消自動同步</translation>
+ </message>
+ <message>
+ <source>Enable auto sync</source>
+ <translation>開啓自動同步</translation>
+ </message>
+ <message>
+ <source>&Quit</source>
+ <translation>退出(&Q)</translation>
+ </message>
+ <message>
+ <source>Show main window</source>
+ <translation>顯示主界面</translation>
+ </message>
+ <message>
+ <source>Settings</source>
+ <translation>設定檔</translation>
+ </message>
+ <message>
+ <source>Open %1 &folder</source>
+ <translation>開啟%1 資料夾(&F)</translation>
+ </message>
+ <message>
+ <source>open %1 folder</source>
+ <translation>開啟%1的資料夾</translation>
+ </message>
+ <message>
+ <source>Open &logs folder</source>
+ <translation>開啟日誌資料夾(&l) </translation>
+ </message>
+ <message>
+ <source>Show file sync errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>&About</source>
+ <translation>關於我們(&A)</translation>
+ </message>
+ <message>
+ <source>Show the application's About box</source>
+ <translation>顯示應用程式的關於對話框</translation>
+ </message>
+ <message>
+ <source>&Online help</source>
+ <translation>在線幫助(&O)</translation>
+ </message>
+ <message>
+ <source>File</source>
+ <translation>檔案</translation>
+ </message>
+ <message>
+ <source>auto sync is disabled</source>
+ <translation>自動同步已被禁用</translation>
+ </message>
+ <message>
+ <source>Uploading</source>
+ <translation>正在上傳</translation>
+ </message>
+ <message>
+ <source>Downloading</source>
+ <translation>正在下載</translation>
+ </message>
+ <message>
+ <source>open %1 log folder</source>
+ <translation>開啟%1的日誌資料夾</translation>
+ </message>
+ <message>
+ <source>open %1 online help</source>
+ <translation>開啟%1的在線幫助</translation>
+ </message>
+ <message>
+ <source>some servers not connected</source>
+ <translation>到伺服器的連接部分運作中</translation>
+ </message>
+ <message>
+ <source>Upload log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>upload %1 log files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please login first</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Repair explorer extension</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Successfully fixed sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Faild to fix sync status icons for Explorer</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>have some sync error</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchResultListView</name>
+ <message>
+ <source>&Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Show in folder</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SearchTab</name>
+ <message>
+ <source>Search files</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>retry</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Failed to search<br/>Please %1</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>ServerStatusDialog</name>
+ <message>
+ <source>Servers connection status</source>
+ <translation>到伺服器連接狀態</translation>
+ </message>
+ <message>
+ <source>connected</source>
+ <translation>已連接</translation>
+ </message>
+ <message>
+ <source>disconnected</source>
+ <translation>已斷開</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>Close</source>
+ <translation>關閉</translation>
+ </message>
+</context>
+<context>
+ <name>SetRepoPasswordDialog</name>
+ <message>
+ <source>Please provide the library password</source>
+ <translation>請輸入資料庫的保護密碼</translation>
+ </message>
+ <message>
+ <source>Provide the password for library %1</source>
+ <translation>請輸入資料庫 %1 的保護密碼</translation>
+ </message>
+ <message>
+ <source>Please enter the password</source>
+ <translation>請輸入密碼</translation>
+ </message>
+ <message>
+ <source>Incorrect password</source>
+ <translation>無法理解的密碼</translation>
+ </message>
+ <message>
+ <source>Unknown error</source>
+ <translation>遭遇未知錯誤</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>確認</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>SettingsDialog</name>
+ <message>
+ <source>Settings</source>
+ <translation>設定檔</translation>
+ </message>
+ <message>
+ <source>Auto start %1 after login</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Hide %1 Icon from the dock</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>None</source>
+ <translation>無代理</translation>
+ </message>
+ <message>
+ <source>HTTP Proxy</source>
+ <translation>HTTP 代理</translation>
+ </message>
+ <message>
+ <source>Socks5 Proxy</source>
+ <translation>SOCKS5 代理</translation>
+ </message>
+ <message>
+ <source>System Proxy</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>You have changed languange. Restart to apply it?</source>
+ <translation>您改變了使用的語言。現在重啓生效嗎?</translation>
+ </message>
+ <message>
+ <source>The proxy host address can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The proxy port is incorrect</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy username can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Proxy password can't be empty</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>Hide main window when started</source>
+ <translation>啟動時隱藏主界面</translation>
+ </message>
+ <message>
+ <source>Notify when libraries are synchronized</source>
+ <translation>當資料庫同步完成時提示</translation>
+ </message>
+ <message>
+ <source>Enable sync temporary files of MSOffice/Libreoffice</source>
+ <translation>同步Microsoft Office 和Libreoffice的臨時檔案</translation>
+ </message>
+ <message>
+ <source>Download speed limit (KB/s):</source>
+ <translation>下載速率 (KB/s):</translation>
+ </message>
+ <message>
+ <source>Upload speed limit (KB/s):</source>
+ <translation>上載速率(KB/s):</translation>
+ </message>
+ <message>
+ <source>Basic</source>
+ <translation>基礎</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library</source>
+ <translation>禁止自動取消同步資料庫</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</source>
+ <translation>禁止當本地資料庫被刪除或無法訪問時,自動取消同步資料庫</translation>
+ </message>
+ <message>
+ <source>Do not unsync a library when not found on server</source>
+ <translation>禁止當資料庫無法在伺服器找到時,自動取消同步自理啊哭</translation>
+ </message>
+ <message>
+ <source>Do not automatically unsync a library when it's not found on server</source>
+ <translation>禁止當資料庫無法在伺服器找到時,自動取消同步自理啊哭</translation>
+ </message>
+ <message>
+ <source>Enable FinderSync Extension</source>
+ <translation>啟用 Finder的延伸功能</translation>
+ </message>
+ <message>
+ <source>Enable Explorer Extension</source>
+ <translation>啟用檔案瀏覽器的延伸功能</translation>
+ </message>
+ <message>
+ <source>Check for updates automatically</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Do not verify server certificate in HTTPS syncing</source>
+ <translation>在HTTPS 同步過程中無法認證伺服器的證書</translation>
+ </message>
+ <message>
+ <source>Enable syncing with an existing folder with a different name</source>
+ <translation>開啟與已存在的不同文件名的資料夾同步的選項</translation>
+ </message>
+ <message>
+ <source>Advanced</source>
+ <translation>高級</translation>
+ </message>
+ <message>
+ <source>Language (need restart)</source>
+ <translation>語言 (需要重啓)</translation>
+ </message>
+ <message>
+ <source>Language</source>
+ <translation>語言</translation>
+ </message>
+ <message>
+ <source>Proxy Type:</source>
+ <translation>代理類型:</translation>
+ </message>
+ <message>
+ <source>Host:</source>
+ <translation>主機地址:</translation>
+ </message>
+ <message>
+ <source>Port:</source>
+ <translation>端口:</translation>
+ </message>
+ <message>
+ <source>0</source>
+ <translation>0</translation>
+ </message>
+ <message>
+ <source>Username:</source>
+ <translation>用戶名:</translation>
+ </message>
+ <message>
+ <source>Password:</source>
+ <translation>密碼:</translation>
+ </message>
+ <message>
+ <source>Proxy server requires a password</source>
+ <translation>代理伺服器需要密碼</translation>
+ </message>
+ <message>
+ <source>Network</source>
+ <translation>網路</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>確認</translation>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation>取消</translation>
+ </message>
+</context>
+<context>
+ <name>SharedItemDelegate</name>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remove Share</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedItemsTableModel</name>
+ <message>
+ <source>Click to edit</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Created by %1</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Write</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Read Only</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Group</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>User</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Permission</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>The previous operation is still in progres</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SharedLinkDialog</name>
+ <message>
+ <source>Share Link</source>
+ <translation>分享連接</translation>
+ </message>
+ <message>
+ <source>Share link:</source>
+ <translation>分享連接:</translation>
+ </message>
+ <message>
+ <source>Direct Download</source>
+ <translation>直接下載</translation>
+ </message>
+ <message>
+ <source>Copy to clipboard</source>
+ <translation>複製到剪貼簿</translation>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation>確認</translation>
+ </message>
+ <message>
+ <source>Upload Link</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Upload link:</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SslConfirmDialog</name>
+ <message>
+ <source>Untrusted Connection</source>
+ <translation>不被信任的連接</translation>
+ </message>
+ <message>
+ <source>%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?</source>
+ <translation>%1 使用了未認證的安全證書。此次連接可能是不安全的,請問還繼續嗎?</translation>
+ </message>
+ <message>
+ <source>Current RSA key fingerprint is %1</source>
+ <translation>目前證書 RSA 指紋是 %1</translation>
+ </message>
+ <message>
+ <source>Previous RSA key fingerprint is %1</source>
+ <translation>先前證書 RSA 指紋是 %1</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>Remember my choice</source>
+ <translation>記住我的選項</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>好</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>不好</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesListView</name>
+ <message>
+ <source>&Open</source>
+ <translation>開啟(&O)</translation>
+ </message>
+ <message>
+ <source>Open this file</source>
+ <translation>開啟此檔案</translation>
+ </message>
+ <message>
+ <source>view on &Web</source>
+ <translation>在瀏覽器中檢視(&W)</translation>
+ </message>
+ <message>
+ <source>view this file on website</source>
+ <translation>在瀏覽器中檢視此檔案</translation>
+ </message>
+</context>
+<context>
+ <name>StarredFilesTab</name>
+ <message>
+ <source>retry</source>
+ <translation>重新嘗試</translation>
+ </message>
+ <message>
+ <source>Failed to get starred files information<br/>Please %1</source>
+ <translation>無法獲取標示檔案的訊息<br/>請 %1</translation>
+ </message>
+ <message>
+ <source>You have no starred files yet.</source>
+ <translation>您沒有標示任何檔案</translation>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsDialog</name>
+ <message>
+ <source>File Sync Errors</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>No sync errors.</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableModel</name>
+ <message>
+ <source>Double click to open the library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Library</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Path</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Error</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Time</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>SyncErrorsTableView</name>
+ <message>
+ <source>Delete file sync error failed</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>TwoFactorDialog</name>
+ <message>
+ <source>Enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Two Factor Authentication</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Please enter the two factor authentication token</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>mText</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Remember this device</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>Cancel</source>
+ <translation type="unfinished"/>
+ </message>
+ <message>
+ <source>OK</source>
+ <translation type="unfinished"/>
+ </message>
+</context>
+<context>
+ <name>UninstallHelperDialog</name>
+ <message>
+ <source>Uninstall %1</source>
+ <translation>移除 %1</translation>
+ </message>
+ <message>
+ <source>Do you want to remove the %1 account information?</source>
+ <translation>您想刪除 帳號 %1 的訊息?</translation>
+ </message>
+ <message>
+ <source>Removing account information...</source>
+ <translation>正在刪除帳號訊息...</translation>
+ </message>
+ <message>
+ <source>Dialog</source>
+ <translation>對話框</translation>
+ </message>
+ <message>
+ <source>text</source>
+ <translation>文本</translation>
+ </message>
+ <message>
+ <source>Yes</source>
+ <translation>好</translation>
+ </message>
+ <message>
+ <source>No</source>
+ <translation>不好</translation>
+ </message>
+</context>
+</TS>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="448"
+ height="448"
+ viewBox="0 0 448 448"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="user.svg"
+ style="fill:#666666"
+ inkscape:export-filename="/data/seafile/seafile-dev/icons/android/user.png"
+ inkscape:export-xdpi="14.464286"
+ inkscape:export-ydpi="14.464286">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="640"
+ inkscape:window-height="480"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="0.52678571"
+ inkscape:cx="142.77966"
+ inkscape:cy="224"
+ inkscape:window-x="364"
+ inkscape:window-y="133"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="svg2" />
+ <path
+ d="m 400,351.25 q 0,30 -18.25,47.375 Q 363.5,416 333.25,416 l -218.5,0 Q 84.5,416 66.25,398.625 48,381.25 48,351.25 48,338 48.875,325.375 49.75,312.75 52.375,298.125 55,283.5 59,271 63,258.5 69.75,246.625 76.5,234.75 85.25,226.375 94,218 106.625,213 q 12.625,-5 27.875,-5 2.25,0 10.5,5.375 8.25,5.375 18.625,12 10.375,6.625 27,12 16.625,5.375 33.375,5.375 16.75,0 33.375,-5.375 16.625,-5.375 27,-12 10.375,-6.625 18.625,-12 8.25,-5.375 10.5,-5.375 15.25,0 27.875,5 12.625,5 21.375,13.375 8.75,8.375 15.5,20.25 Q 385,258.5 389,271 q 4,12.5 6.625,27.125 2.625,14.625 3.5,27.25 Q 400,338 400,351.25 z M 320,128 q 0,39.75 -28.125,67.875 Q 263.75,224 224,224 184.25,224 156.125,195.875 128,167.75 128,128 128,88.25 156.125,60.125 184.25,32 224,32 263.75,32 291.875,60.125 320,88.25 320,128 z"
+ id="path4"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="30"
+ height="42"
+ viewBox="0 0 30 42.000001"
+ id="svg3009"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="long-arrow-up.svg"
+ inkscape:export-filename="/tmp/arrow-down.png"
+ inkscape:export-xdpi="33"
+ inkscape:export-ydpi="33">
+ <metadata
+ id="metadata3017">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3015" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview3013"
+ showgrid="false"
+ inkscape:zoom="10.216667"
+ inkscape:cx="5.2687853"
+ inkscape:cy="13.548125"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg3009"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0" />
+ <path
+ d="m 29.885105,27.255666 c -0.234761,-0.307603 -0.61242,-0.461404 -1.132978,-0.461404 l -7.657433,0 0,-26.01573 c 0,-0.226843 -0.117381,-0.41331 -0.352143,-0.5594 C 20.50779,0.073045 20.208142,0 19.843605,0 L 10.16077,0 C 9.7962333,0 9.4965846,0.07306 9.2618234,0.219132 9.0270617,0.365222 8.9096808,0.551689 8.9096808,0.778532 l 0,26.01573 -7.6574329,0 c -0.54680408,0 -0.92446325,0.153801 -1.13297746,0.461404 -0.20851508,0.307603 -0.14362808,0.591158 0.19466102,0.85067 L 13.984038,41.756369 c 0.261008,0.162421 0.560657,0.243632 0.898948,0.243632 0.364535,0 0.677306,-0.08122 0.938315,-0.243632 L 29.686068,28.106336 c 0.338289,-0.259512 0.403177,-0.543067 0.194662,-0.85067 z"
+ id="path3011"
+ inkscape:connector-curvature="0"
+ style="fill:#b1b1b2;fill-opacity:1"
+ sodipodi:nodetypes="cscsssscscssccscccc" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="16" viewBox="0 0 9 16">
+<g>
+ <line stroke-width="1" x1="" y1="" x2="" y2="" stroke="#449FDB" opacity=""></line>
+</g>
+ <path d="M0 6.286q0-0.232 0.17-0.402t0.402-0.17h8q0.232 0 0.402 0.17t0.17 0.402-0.17 0.402l-4 4q-0.17 0.17-0.402 0.17t-0.402-0.17l-4-4q-0.17-0.17-0.17-0.402z" fill="#000000"></path>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="16"
+ height="16"
+ viewBox="0 0 16 16"
+ id="svg4083"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="caret-right.svg"
+ inkscape:export-filename="/data/github/seafile-client/images/caret-down@2x.png"
+ inkscape:export-xdpi="180"
+ inkscape:export-ydpi="180">
+ <metadata
+ id="metadata4095">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs4093" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1295"
+ inkscape:window-height="744"
+ id="namedview4091"
+ showgrid="false"
+ inkscape:zoom="14.75"
+ inkscape:cx="-9"
+ inkscape:cy="8"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4083" />
+ <g
+ id="g4085">
+ <line
+ x1="0"
+ y1="0"
+ x2="0"
+ y2="0"
+ opacity=""
+ id="line4087"
+ style="stroke:#449fdb;stroke-width:1" />
+ </g>
+ <path
+ d="m 3.6144551,4.7033531 8.7710889,0 q 0.254362,0 0.440748,0.2178967 0.186386,0.2178965 0.186386,0.5152612 0,0.2973647 -0.186386,0.5152613 L 8.440747,11.078751 q -0.1863858,0.217896 -0.4407474,0.217896 -0.2543617,0 -0.4407473,-0.217896 L 3.1737081,5.9517724 q -0.186386,-0.2178968 -0.186386,-0.5152613 0,-0.2973648 0.186386,-0.5152613 0.186386,-0.2178965 0.440747,-0.2178965 z"
+ id="path4089"
+ inkscape:connector-curvature="0"
+ style="fill:#3f3f3f;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9" height="16" viewBox="0 0 9 16">
+<g>
+ <line stroke-width="1" x1="" y1="" x2="" y2="" stroke="#449FDB" opacity=""></line>
+</g>
+ <path d="M0 10.857q0-0.232 0.17-0.402l4-4q0.17-0.17 0.402-0.17t0.402 0.17l4 4q0.17 0.17 0.17 0.402t-0.17 0.402-0.402 0.17h-8q-0.232 0-0.402-0.17t-0.17-0.402z" fill="#000000"></path>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="16"
+ height="16"
+ viewBox="0 0 16 16"
+ id="svg3060"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="clock.svg"
+ inkscape:export-filename="/home/lin/Downloads/clock@2x.png"
+ inkscape:export-xdpi="194.52686"
+ inkscape:export-ydpi="194.52686">
+ <metadata
+ id="metadata3068">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3066" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1855"
+ inkscape:window-height="1056"
+ id="namedview3064"
+ showgrid="false"
+ inkscape:zoom="40.172504"
+ inkscape:cx="9.4836957"
+ inkscape:cy="6.5090134"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg3060" />
+ <path
+ d="M 10.121764,11.430169 7.0746779,8.3830833 V 4.2987118 H 8.9253221 V 7.6169167 L 11.430169,10.121764 z M 8,0.59742355 C 3.9119271,0.59742355 0.59742355,3.9119271 0.59742355,8 c 0,4.088073 3.31450355,7.402577 7.40257645,7.402577 4.088073,0 7.402577,-3.314504 7.402577,-7.402577 C 15.402577,3.9119271 12.088073,0.59742355 8,0.59742355 z M 8,13.551933 C 4.9334827,13.551933 2.4480676,11.066517 2.4480676,8 2.4480676,4.9334827 4.9334827,2.4480676 8,2.4480676 c 3.066517,0 5.551933,2.4854151 5.551933,5.5519324 0,3.066517 -2.485416,5.551933 -5.551933,5.551933 z"
+ id="path3062"
+ style="fill:#999999;fill-opacity:1"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="16"
+ height="16"
+ viewBox="0 0 16 16"
+ id="svg4767"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="close.svg"
+ inkscape:export-filename="/data/github/seafile-client/images/close.png"
+ inkscape:export-xdpi="180"
+ inkscape:export-ydpi="180">
+ <metadata
+ id="metadata4779">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs4777" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1295"
+ inkscape:window-height="744"
+ id="namedview4775"
+ showgrid="false"
+ inkscape:zoom="14.75"
+ inkscape:cx="8"
+ inkscape:cy="8"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4767" />
+ <g
+ id="g4769">
+ <line
+ stroke-width="1"
+ x1=""
+ y1=""
+ x2=""
+ y2=""
+ stroke="#449FDB"
+ opacity=""
+ id="line4771" />
+ </g>
+ <path
+ d="m 13.389468,11.292004 c 0,0 0,0 0,0 L 9.9957702,7.898305 13.389468,4.5046068 c 0,0 0,0 0,0 0.03636,-0.036356 0.06292,-0.079004 0.0797,-0.1244495 0.04614,-0.1244496 0.01958,-0.2698739 -0.0797,-0.369853 L 11.786305,2.407142 c -0.09998,-0.099979 -0.245403,-0.126547 -0.369852,-0.079703 -0.04544,0.01678 -0.08809,0.043347 -0.12445,0.079703 0,0 0,0 0,0 L 7.8983051,5.8008402 4.5046069,2.407142 c 0,0 0,0 0,0 C 4.468251,2.370786 4.4256026,2.3442182 4.3801574,2.3274385 4.2557078,2.2812944 4.1102835,2.3071631 4.0103044,2.407142 L 2.4071421,4.0103043 c -0.099979,0.099979 -0.126547,0.2454034 -0.079704,0.369853 0.01678,0.045445 0.043348,0.088093 0.079704,0.1244495 0,0 0,0 0,0 L 5.8008403,7.898305 2.4071421,11.292004 c 0,0 0,0 0,0 -0.036356,0.03636 -0.062924,0.079 -0.079704,0.124449 -0.046144,0.124449 -0.020275,0.269874 0.079704,0.369853 l 1.6031623,1.603163 c 0.099979,0.09998 0.2454034,0.126546 0.369853,0.0797 0.045445,-0.01678 0.088093,-0.04335 0.1244495,-0.0797 0,0 0,0 0,0 L 7.8983051,9.9957703 11.292003,13.389469 c 0,0 0,0 0,0 0.03636,0.03636 0.079,0.06292 0.12445,0.0797 0.124449,0.04614 0.269873,0.02027 0.369852,-0.0797 l 1.603163,-1.603163 c 0.09998,-0.09998 0.126546,-0.245404 0.0797,-0.369853 -0.01678,-0.04545 -0.04335,-0.08809 -0.0797,-0.124449 z"
+ id="path4773"
+ inkscape:connector-curvature="0"
+ style="fill:#585859" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg3024"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="cloud.svg"
+ inkscape:export-filename="/tmp/cloud.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata3032">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3030" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview3028"
+ showgrid="false"
+ inkscape:zoom="9.95"
+ inkscape:cx="-3.3768842"
+ inkscape:cy="25.448101"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg3024" />
+ <path
+ d="m 57.999999,37.133483 q 0,4.637775 -3.281461,7.918364 -3.281462,3.28059 -7.918364,3.281461 H 15.066608 q -5.395637,0 -9.231123,-3.835485 Q 2,40.662337 2,35.2667 2,31.416406 4.0706219,28.222927 6.1412437,25.029448 9.524625,23.454486 q -0.05836,-0.817099 -0.05836,-1.254395 0,-6.183119 4.374699,-10.55869 4.374701,-4.3755723 10.558691,-4.374701 4.608157,0 8.356532,2.5662817 3.748374,2.5662813 5.46881,6.7083963 2.041877,-1.808418 4.841615,-1.808418 3.09156,0 5.278909,2.187351 2.187352,2.18735 2.187352,5.27891 0,2.18735 -1.196031,4.025386 3.762312,0.874591 6.212737,3.922597 Q 58,33.195207 58,37.132612 z"
+ id="path3026"
+ inkscape:connector-curvature="0"
+ style="fill:#f17f49;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="28"
+ height="28"
+ viewBox="0 0 28 27.999999"
+ id="svg3033"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="hdd-o.svg"
+ inkscape:export-filename="/home/lin/Downloads/disk@2x.png"
+ inkscape:export-xdpi="102.85714"
+ inkscape:export-ydpi="102.85714">
+ <metadata
+ id="metadata3041">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3039" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1855"
+ inkscape:window-height="1056"
+ id="namedview3037"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="16.232143"
+ inkscape:cx="3.3413679"
+ inkscape:cy="11.153118"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg3033" />
+ <path
+ d="m 18.863893,19.113731 q 0,0.579047 -0.411841,0.99089 -0.411841,0.411841 -0.990889,0.411841 -0.579047,0 -0.990889,-0.411841 -0.411842,-0.411843 -0.411842,-0.99089 0,-0.579046 0.411842,-0.990888 0.411842,-0.411842 0.990889,-0.411842 0.579048,0 0.990889,0.411842 0.411841,0.411842 0.411841,0.990888 z m 4.488737,0 q 0,0.579047 -0.411841,0.99089 -0.411842,0.411841 -0.990888,0.411841 -0.579048,0 -0.99089,-0.411841 -0.411841,-0.411843 -0.411841,-0.99089 0,-0.579046 0.411841,-0.990888 0.411842,-0.411842 0.99089,-0.411842 0.579046,0 0.990888,0.411842 0.411841,0.411842 0.411841,0.990888 z m 1.963823,2.805462 V 16.30827 q 0,-0.227803 -0.166083,-0.395008 -0.166084,-0.167206 -0.395009,-0.166083 H 3.43386 q -0.2278033,0 -0.3950089,0.166083 -0.1672054,0.166084 -0.1660832,0.395008 v 5.610923 q 0,0.227803 0.1660832,0.395008 0.1660833,0.167206 0.3950089,0.166083 h 21.321501 q 0.227804,0 0.395009,-0.166083 0.167205,-0.166083 0.166083,-0.395008 z M 3.7491938,13.50281 H 24.440028 L 21.68731,5.0516402 Q 21.616611,4.8238368 21.406763,4.6745864 21.196914,4.5253354 20.951156,4.5253354 H 7.2391871 q -0.2457584,0 -0.4556069,0.149251 -0.2098484,0.1492504 -0.2805461,0.3770538 z m 23.8116282,2.80546 v 5.610923 q 0,1.156972 -0.823684,1.981777 -0.823683,0.824805 -1.981777,0.823684 H 3.43386 q -1.156972,0 -1.9817776,-0.823684 Q 0.62727696,23.077286 0.62839914,21.919193 V 16.30827 q 0,-0.438773 0.28054604,-1.315199 L 4.3630287,4.3671073 Q 4.6615297,3.4379388 5.4672581,2.8588916 6.2729864,2.2798446 7.2380649,2.2798446 H 20.950034 q 0.963956,0 1.770807,0.579047 0.80685,0.5790472 1.104229,1.5082157 L 27.279154,14.993071 Q 27.5597,15.869497 27.5597,16.30827 z"
+ id="path3035"
+ style="fill:#999999;fill-opacity:1"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg3930"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="download-alt.svg"
+ inkscape:export-filename="/tmp/download.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <metadata
+ id="metadata3938">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3936" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview3934"
+ showgrid="false"
+ inkscape:zoom="7.375"
+ inkscape:cx="-9"
+ inkscape:cy="26.847458"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg3930" />
+ <path
+ d="m 43.651813,48.750912 q 0,-0.845851 -0.578568,-1.465655 -0.578568,-0.619805 -1.372178,-0.617982 -0.793611,0.0018 -1.372179,0.617982 -0.578568,0.616158 -0.578568,1.465655 0,0.849497 0.578568,1.465656 0.578568,0.616158 1.372179,0.617981 0.79361,0.0018 1.372178,-0.617981 0.578568,-0.619805 0.578568,-1.465656 z m 7.802987,0 q 0,-0.845851 -0.578568,-1.465655 -0.578568,-0.619805 -1.372179,-0.617982 -0.793611,0.0018 -1.372178,0.617982 -0.578568,0.616158 -0.578568,1.465655 0,0.849497 0.578568,1.465656 0.578567,0.616158 1.372178,0.617981 0.793611,0.0018 1.372179,-0.617981 0.578568,-0.619805 0.578568,-1.465656 z m 3.899787,-7.291818 v 10.416362 q 0,1.30159 -0.853345,2.213067 Q 53.647897,55 52.42932,55 H 7.5672672 q -1.218577,0 -2.071922,-0.911477 -0.853345,-0.911477 -0.853345,-2.213067 V 41.459094 q 0,-1.301589 0.853345,-2.213066 0.853345,-0.911478 2.071922,-0.911478 H 21.73962 l 4.11483,4.427957 q 1.768131,1.822954 4.14555,1.822954 2.377419,0 4.14555,-1.822954 L 38.2911,38.33455 h 14.141633 q 1.218577,0 2.071922,0.911478 0.853345,0.911477 0.853345,2.213066 z m -9.903922,-18.52304 q 0.518833,1.334403 -0.426673,2.278693 l -13.65352,14.583636 q -0.547847,0.617981 -1.372179,0.617981 -0.824331,0 -1.372178,-0.617981 L 14.972595,25.214747 q -0.945507,-0.94429 -0.426673,-2.278693 0.518834,-1.268776 1.798851,-1.268776 h 7.80128 V 7.0836422 q 0,-0.8458509 0.578568,-1.4656554 0.578568,-0.6198045 1.372179,-0.6179816 h 7.80128 q 0.791904,0 1.372179,0.6179816 0.580274,0.6179816 0.578568,1.4656554 V 21.667278 h 7.80128 q 1.280017,0 1.798851,1.268776 z"
+ id="path3932"
+ inkscape:connector-curvature="0"
+ style="fill:#585859;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg4411"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="exclamation.svg"
+ inkscape:export-filename="/tmp/exclamation.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata4419">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs4417" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview4415"
+ showgrid="false"
+ inkscape:zoom="10.216667"
+ inkscape:cx="30"
+ inkscape:cy="30"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4411" />
+ <path
+ d="m 35.619886,42.17744 v 6.557117 q 0,0.7615 -0.556043,1.317543 -0.556044,0.556044 -1.317544,0.556044 h -7.493473 q -0.7615,0 -1.317544,-0.556044 Q 24.37924,49.496057 24.37924,48.734557 V 42.17744 q 0,-0.7615 0.556042,-1.317543 0.556044,-0.556044 1.317544,-0.556044 h 7.493473 q 0.7615,0 1.317544,0.556044 0.556043,0.556043 0.556043,1.317543 z m 0.87778,-30.911997 -0.820077,22.481293 q -0.02885,0.7615 -0.599758,1.317544 -0.570906,0.556043 -1.331532,0.556043 h -7.493473 q -0.7615,0 -1.331532,-0.556043 -0.570031,-0.556044 -0.599757,-1.317544 L 23.50146,11.265443 Q 23.47261,10.503944 24.013789,9.9479 24.554971,9.391856 25.316469,9.391856 h 9.367061 q 0.7615,0 1.30268,0.556044 0.541181,0.556044 0.51233,1.317543 z"
+ id="path4413"
+ style="fill:#f17f49;fill-opacity:1"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg5116"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="folder-open.svg"
+ inkscape:export-filename="/tmp/folder-open.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata5124">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs5122" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview5120"
+ showgrid="false"
+ inkscape:zoom="10.216667"
+ inkscape:cx="30"
+ inkscape:cy="30"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg5116" />
+ <path
+ d="M 46.370312,51.281406 56.1925,25.088906 H 13.629688 L 3.8075,51.281406 z M 10.355625,21.814843 3.8075,51.281406 V 8.718594 h 14.733281 l 6.548125,6.548125 h 21.281406 v 6.548124 z"
+ id="path5118"
+ inkscape:connector-curvature="0"
+ style="fill:#585859;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg7784"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="info-sign.svg"
+ inkscape:export-filename="/tmp/info.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <metadata
+ id="metadata7792">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs7790" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview7788"
+ showgrid="false"
+ inkscape:zoom="7.375"
+ inkscape:cx="-2.6355932"
+ inkscape:cy="26.847458"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg7784" />
+ <path
+ d="M 39.165998,47.186998 V 41.458 q 0,-0.501314 -0.322846,-0.824159 -0.322845,-0.322845 -0.824156,-0.322845 h -3.437 V 21.976994 q 0,-0.501312 -0.322844,-0.824158 -0.322846,-0.322845 -0.824159,-0.322845 H 21.976994 q -0.501312,0 -0.824158,0.322845 -0.322845,0.322846 -0.322845,0.824158 v 5.729 q 0,0.501313 0.322845,0.824158 0.322846,0.322846 0.824158,0.322846 h 3.437 v 11.457998 h -3.437 q -0.501312,0 -0.824158,0.322845 -0.322845,0.322845 -0.322845,0.824159 v 5.728998 q 0,0.501314 0.322845,0.824159 0.322846,0.322845 0.824158,0.322845 h 16.042002 q 0.501311,0 0.824156,-0.322845 0.322846,-0.322845 0.322846,-0.824159 z m -4.584002,-32.084 V 9.3739977 q 0,-0.5013124 -0.322844,-0.824158 -0.322846,-0.3228456 -0.824159,-0.3228456 h -6.876002 q -0.501313,0 -0.824159,0.3228456 -0.322844,0.3228456 -0.322844,0.824158 v 5.7290003 q 0,0.501312 0.322844,0.824156 Q 26.057678,16.25 26.558991,16.25 h 6.876002 q 0.501313,0 0.824159,-0.322846 0.322844,-0.322844 0.322844,-0.824156 z M 57.5,30 q 0,7.483594 -3.687656,13.804142 Q 50.12469,50.12469 43.804142,53.812344 37.483594,57.5 30,57.5 22.516406,57.5 16.195858,53.812344 9.87531,50.12469 6.1876549,43.804142 2.5,37.483594 2.5,30 2.5,22.516406 6.1876549,16.195858 9.87531,9.8753101 16.195858,6.1876554 22.516406,2.5 30,2.5 37.483594,2.5 43.804142,6.1876554 50.12469,9.8753101 53.812344,16.195858 57.5,22.516406 57.5,30 z"
+ id="path7786"
+ inkscape:connector-curvature="0"
+ style="fill:#585859;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="32"
+ height="32"
+ viewBox="0 0 32 32"
+ id="svg9579"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="link.svg"
+ inkscape:export-filename="/tmp/link-red.png"
+ inkscape:export-xdpi="168.75"
+ inkscape:export-ydpi="168.75">
+ <metadata
+ id="metadata9587">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs9585" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview9583"
+ showgrid="false"
+ inkscape:zoom="7.375"
+ inkscape:cx="-8"
+ inkscape:cy="16"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg9579" />
+ <path
+ d="M 27.208113,4.8946702 27.105734,4.7922939 c -2.390392,-2.390392 -6.301795,-2.390392 -8.692187,0 l -5.53804,5.5388521 c -2.390392,2.390392 -2.390392,6.301794 0,8.691373 l 0.102379,0.102378 c 0.199062,0.199065 0.410314,0.378627 0.628065,0.545193 l 2.027204,-2.027204 c -0.236441,-0.139751 -0.459879,-0.306313 -0.663005,-0.50944 l -0.102378,-0.102378 c -1.297573,-1.297574 -1.297573,-3.409275 0,-4.706848 l 5.538039,-5.5380376 c 1.297571,-1.297572 3.409274,-1.297572 4.706845,0 l 0.102378,0.1023752 c 1.297573,1.2975718 1.297573,3.4100864 0,4.7068454 l -2.505768,2.505768 c 0.434692,1.074133 0.641068,2.218952 0.623194,3.361335 l 3.874838,-3.874839 c 2.390392,-2.390391 2.390392,-6.301794 0,-8.6913739 z M 19.02293,12.87429 c -0.199066,-0.199066 -0.410317,-0.378629 -0.628069,-0.54438 l -2.0272,2.027201 c 0.236437,0.139751 0.459878,0.306316 0.663005,0.509443 l 0.102378,0.102378 c 1.29757,1.297571 1.29757,3.409274 0,4.706845 l -5.538853,5.538854 c -1.297571,1.29757 -3.409274,1.29757 -4.7068458,0 L 6.7849689,25.112252 c -1.2975718,-1.298383 -1.2975718,-3.409274 0,-4.706846 L 9.290734,17.899637 C 8.8560436,16.825503 8.6496672,15.680684 8.6675423,14.538301 L 4.792702,18.41314 c -2.3903919,2.390392 -2.3903919,6.301795 0,8.692187 l 0.1023752,0.102378 c 2.3903922,2.390393 6.3017958,2.390393 8.6921878,0 l 5.53804,-5.538039 c 2.390392,-2.390393 2.390392,-6.301795 0,-8.692188 L 19.022926,12.8751 z"
+ id="path9581"
+ style="fill:#ff2a2a;fill-opacity:1"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg3065"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="ok.svg"
+ inkscape:export-filename="/tmp/ok.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata3073">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3071" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview3069"
+ showgrid="false"
+ inkscape:zoom="9.95"
+ inkscape:cx="30"
+ inkscape:cy="30"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#54c73f;fill-opacity:1"
+ id="path3845"
+ sodipodi:cx="15.979899"
+ sodipodi:cy="4.924623"
+ sodipodi:rx="7.3366833"
+ sodipodi:ry="6.3316584"
+ d="m 23.316583,4.924623 a 7.3366833,6.3316584 0 1 1 -14.6733669,0 7.3366833,6.3316584 0 1 1 14.6733669,0 z"
+ transform="matrix(4.0890412,0,0,4.7380953,-35.342467,6.6666668)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="ok">
+ <path
+ d="m 47.949308,21.616068 q 0,0.926208 -0.648828,1.575037 L 27.382549,43.109034 q -0.648828,0.648829 -1.575034,0.648829 -0.926206,0 -1.575034,-0.648829 L 12.698828,31.575379 Q 12.05,30.926551 12.05,30.000344 q 0,-0.926206 0.648828,-1.575033 l 3.150068,-3.15007 q 0.648828,-0.648829 1.575035,-0.648829 0.926206,0 1.575035,0.648829 l 6.80924,6.832067 15.192825,-15.216342 q 0.648828,-0.648828 1.575034,-0.648828 0.926209,0 1.575037,0.648828 l 3.15007,3.150069 Q 47.95,20.689862 47.95,21.616068 z"
+ id="path3067"
+ style="fill:#ffffff;fill-opacity:1"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg6322"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="pause.svg"
+ inkscape:export-filename="/tmp/pause.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata6330">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6328" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview6326"
+ showgrid="false"
+ inkscape:zoom="3.9333333"
+ inkscape:cx="-64.245763"
+ inkscape:cy="30"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg6322" />
+ <path
+ d="M 55,7.0834549 V 52.916545 q 0,0.846799 -0.618328,1.465127 Q 53.763344,55 52.916545,55 H 36.249878 Q 35.40308,55 34.784752,54.381672 34.166424,53.763344 34.166424,52.916545 V 7.0834549 q 0,-0.8467985 0.618328,-1.4651267 Q 35.40308,5 36.249878,5 H 52.916545 Q 53.763344,5 54.381672,5.6183282 55,6.2366564 55,7.0834549 z m -29.166424,0 V 52.916545 q 0,0.846799 -0.618328,1.465127 Q 24.59692,55 23.750122,55 H 7.083455 Q 6.2366565,55 5.6183282,54.381672 5.0000001,53.763344 5.0000001,52.916545 V 7.0834549 q 0,-0.8467985 0.6183281,-1.4651267 Q 6.2366565,5 7.083455,5 h 16.666667 q 0.846798,0 1.465126,0.6183282 0.618328,0.6183282 0.618328,1.4651267 z"
+ id="path6324"
+ inkscape:connector-curvature="0"
+ style="fill:#f17f49;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg8926"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="play.svg"
+ inkscape:export-filename="/tmp/play.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <metadata
+ id="metadata8934">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8932" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview8930"
+ showgrid="false"
+ inkscape:zoom="7.375"
+ inkscape:cx="-3.6355932"
+ inkscape:cy="32.271186"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg8926" />
+ <path
+ d="m 47.530175,30.798134 -34.210638,19.01248 q -0.592923,0.334693 -1.017058,0.0779 -0.424134,-0.256786 -0.425577,-0.927611 V 11.039808 q 0,-0.669382 0.425577,-0.927614 0.425578,-0.2582325 1.017058,0.0779 l 34.210638,19.012484 q 0.592922,0.33469 0.592922,0.799218 0,0.464529 -0.592922,0.799221 z"
+ id="path8928"
+ inkscape:connector-curvature="0"
+ style="fill:#585859;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="16"
+ height="16"
+ viewBox="0 0 16 16"
+ id="svg4680"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="plus.svg"
+ inkscape:export-filename="/data/github/seafile-client/images/plus.png"
+ inkscape:export-xdpi="180"
+ inkscape:export-ydpi="180">
+ <metadata
+ id="metadata4692">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs4690" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1295"
+ inkscape:window-height="744"
+ id="namedview4688"
+ showgrid="false"
+ inkscape:zoom="14.75"
+ inkscape:cx="-1.5677966"
+ inkscape:cy="8"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg4680" />
+ <g
+ id="g4682">
+ <line
+ x1="0"
+ y1="0"
+ x2="0"
+ y2="0"
+ opacity=""
+ id="line4684"
+ style="stroke:#449fdb;stroke-width:1" />
+ </g>
+ <path
+ d="M 1.715,8.857 V 7.143 q 0,-0.357 0.25,-0.607 0.25,-0.25 0.607,-0.25 H 6.286 V 2.572 q 0,-0.357 0.25,-0.607 0.25,-0.25 0.607,-0.25 h 1.714 q 0.357,0 0.607,0.25 0.25,0.25 0.25,0.607 v 3.714 h 3.714 q 0.357,0 0.607,0.25 0.25,0.25 0.25,0.607 v 1.714 q 0,0.357 -0.25,0.607 -0.25,0.25 -0.607,0.25 H 9.714 v 3.714 q 0,0.357 -0.25,0.607 -0.25,0.25 -0.607,0.25 H 7.143 q -0.357,0 -0.607,-0.25 -0.25,-0.25 -0.25,-0.607 V 9.714 H 2.572 q -0.357,0 -0.607,-0.25 -0.25,-0.25 -0.25,-0.607 z"
+ id="path4686"
+ inkscape:connector-curvature="0"
+ style="fill:#585859" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg5006"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="question.svg"
+ inkscape:export-filename="/tmp/question.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata5014">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs5012" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview5010"
+ showgrid="false"
+ inkscape:zoom="3.9333333"
+ inkscape:cx="-28"
+ inkscape:cy="30"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg5006" />
+ <path
+ d="m 34.890523,42.0545 v 8.036 q 0,0.536 -0.402,0.938 -0.402,0.402 -0.938,0.402 h -8.036 q -0.536,0 -0.938,-0.402 -0.402,-0.402 -0.402,-0.938 v -8.036 q 0,-0.536 0.402,-0.938 0.402,-0.402 0.938,-0.402 h 8.036 q 0.536,0 0.938,0.402 0.402,0.402 0.402,0.938 z m 10.581,-20.09 q 0,1.808 -0.519,3.382 -0.519,1.574 -1.172,2.561 -0.653,0.987 -1.842,1.992 -1.189,1.005 -1.925,1.456 -0.736,0.451 -2.042,1.189 -1.373,0.77 -2.294,2.176 -0.921,1.406 -0.921,2.243 0,0.569 -0.402,1.088 -0.402,0.519 -0.938,0.519 h -8.036 q -0.502,0 -0.854,-0.619 -0.352,-0.619 -0.352,-1.256 v -1.507 q 0,-2.779 2.176,-5.24 2.176,-2.461 4.788,-3.633 1.975,-0.904 2.813,-1.875 0.838,-0.971 0.837,-2.545 0,-1.406 -1.557,-2.478 -1.557,-1.072 -3.599,-1.071 -2.176,0 -3.616,0.971 -1.172,0.837 -3.583,3.85 -0.435,0.536 -1.038,0.536 -0.402,0 -0.837,-0.268 l -5.491,-4.185 q -0.435,-0.335 -0.519,-0.837 -0.084,-0.502 0.184,-0.938 5.357,-8.906 15.536,-8.906 2.679,0 5.391,1.038 2.712,1.038 4.888,2.779 2.176,1.741 3.549,4.269 1.373,2.528 1.373,5.307 z"
+ id="path5008"
+ inkscape:connector-curvature="0"
+ style="fill:#f17f49;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg5029"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="refresh.svg"
+ inkscape:export-filename="/tmp/refresh.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata5037">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs5035" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview5033"
+ showgrid="false"
+ inkscape:zoom="10.216667"
+ inkscape:cx="6.7047318"
+ inkscape:cy="30"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg5029" />
+ <path
+ d="m 32.426902,6.5012004 8.535401,8.5354006 q 0.495053,0.495053 0.496132,1.219482 0.0011,0.724429 -0.496088,1.219464 l -8.53509,8.535091 q -0.800165,0.800163 -1.886283,0.362712 -1.066912,-0.418246 -1.04773,-1.581172 l -9.5e-5,-5.257712 q -5.429479,0.210081 -9.258534,4.039136 -1.981208,1.981208 -3.010725,4.553499 -1.029517,2.57229 -1.029469,5.201145 4.8e-5,2.628856 1.029659,5.201184 1.029611,2.572328 3.010891,4.553609 1.98128,1.98128 4.553608,3.01089 2.572328,1.029611 5.201184,1.029659 2.628855,4.8e-5 5.201145,-1.029469 2.572291,-1.029517 4.553499,-3.010725 2.267133,-2.267132 3.295575,-5.277923 1.028444,-3.010787 0.609091,-6.210446 -0.05761,-0.32434 0.210168,-0.666811 0.266721,-0.266723 0.647605,-0.304057 l 5.238508,0.0193 q 0.324339,-0.01919 0.571865,0.209125 0.24753,0.228319 0.285941,0.571866 0.438582,4.590903 -1.132891,8.925712 -1.571473,4.334809 -4.84788,7.611217 -2.972346,2.972345 -6.838784,4.51502 -3.866437,1.542675 -7.79265,1.542603 -3.926212,-7.1e-5 -7.792707,-1.542887 Q 18.331754,50.933294 15.3593,47.96084 12.386847,44.988387 10.844031,41.121892 9.3012151,37.255398 9.301144,33.329186 q -7.2e-5,-3.926214 1.542603,-7.792651 1.542675,-3.866438 4.51502,-6.838784 2.800577,-2.800576 6.477105,-4.362459 3.676528,-1.561883 7.640081,-1.675969 l 0.01805,-4.9344375 q -0.03843,-1.1437238 1.066877,-1.6003392 1.066898,-0.4182076 1.867092,0.3819863 z"
+ id="path5031"
+ inkscape:connector-curvature="0"
+ style="fill:#585859;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="72"
+ height="72"
+ viewBox="0 0 72 72"
+ id="svg2"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="library-enc.svg"
+ inkscape:export-filename="/tmp/encrypted-repo.png"
+ inkscape:export-xdpi="45"
+ inkscape:export-ydpi="45">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="8.5138889"
+ inkscape:cx="36"
+ inkscape:cy="36"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <path
+ d="m 60.544243,60.545075 c 0,0 -43.636062,0 -49.090152,0 C 6,60.545075 6,55.090984 6,55.090984 V 36.000416 L 19.636477,11.454925 H 52.363523 L 66,36.000416 c 0,0 0,13.636478 0,19.090568 0,5.454091 -5.454091,5.454091 -5.454091,5.454091 z M 49.635227,16.909014 h -27.27212 l -9.545701,19.090569 h 12.272329 c 0,0 5.454091,0 5.454091,5.454091 v 2.727462 h 10.909016 v -2.727462 c 0,0 0,-5.454091 5.45409,-5.454091 h 12.272329 l -9.5457,-19.090569 z m 10.909016,24.54466 H 47.565256 c -0.379161,0.71749 -0.657491,1.576645 -0.657491,2.727462 0,5.45409 -5.454091,5.45409 -5.454091,5.45409 H 30.544659 c 0,0 -5.45409,0 -5.45409,-5.45409 0,-1.150817 -0.27833,-2.009972 -0.657492,-2.727462 H 11.454091 V 55.090151 H 60.544243 V 41.453674 z M 23.72642,27.818029 h 24.545494 l 1.363313,2.727462 h -27.27212 l 1.363313,-2.727462 z m 2.726629,-5.454924 h 19.090568 l 1.363315,2.727462 H 25.088901 l 1.363315,-2.727462 z"
+ id="path4"
+ style="fill:#999999;fill-opacity:1"
+ inkscape:connector-curvature="0" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="lock"
+ style="display:none">
+ <g
+ style="fill:#ff6600"
+ id="g3008"
+ transform="matrix(0.08874904,0,0,0.08874904,42.893874,32.04591)">
+ <path
+ id="path3000"
+ d="m 176,256 q 0,-13.25 -9.375,-22.625 Q 157.25,224 144,224 130.75,224 121.375,233.375 112,242.75 112,256 q 0,9.25 4.75,16.75 4.75,7.5 12.75,11.75 l -17.25,57.25 q -1.25,3.75 1.25,7 2.5,3.25 6.5,3.25 l 48,0 q 4,0 6.5,-3.25 2.5,-3.25 1.25,-7 L 158.5,284.5 q 8,-4.25 12.75,-11.75 Q 176,265.25 176,256 z m -96,-64 128,0 0,-48 Q 208,117.5 189.25,98.75 170.5,80 144,80 117.5,80 98.75,98.75 80,117.5 80,144 l 0,48 z m 208,24 0,144 q 0,10 -7,17 -7,7 -17,7 L 24,384 Q 14,384 7,377 0,370 0,360 L 0,216 q 0,-10 7,-17 7,-7 17,-7 l 8,0 0,-48 q 0,-46 33,-79 33,-33 79,-33 46,0 79,33 33,33 33,79 l 0,48 8,0 q 10,0 17,7 7,7 7,17 z"
+ inkscape:connector-curvature="0"
+ style="fill:#ff6600" />
+ </g>
+ </g>
+ <g
+ style="fill:#ff6600"
+ id="g3008-1"
+ transform="matrix(0.08874904,0,0,0.08874904,40.440276,26.465444)">
+ <path
+ id="path3000-6"
+ d="m 176,256 q 0,-13.25 -9.375,-22.625 Q 157.25,224 144,224 130.75,224 121.375,233.375 112,242.75 112,256 q 0,9.25 4.75,16.75 4.75,7.5 12.75,11.75 l -17.25,57.25 q -1.25,3.75 1.25,7 2.5,3.25 6.5,3.25 l 48,0 q 4,0 6.5,-3.25 2.5,-3.25 1.25,-7 L 158.5,284.5 q 8,-4.25 12.75,-11.75 Q 176,265.25 176,256 z m -96,-64 128,0 0,-48 Q 208,117.5 189.25,98.75 170.5,80 144,80 117.5,80 98.75,98.75 80,117.5 80,144 l 0,48 z m 208,24 0,144 q 0,10 -7,17 -7,7 -17,7 L 24,384 Q 14,384 7,377 0,370 0,360 L 0,216 q 0,-10 7,-17 7,-7 17,-7 l 8,0 0,-48 q 0,-46 33,-79 33,-33 79,-33 46,0 79,33 33,33 33,79 l 0,48 8,0 q 10,0 17,7 7,7 7,17 z"
+ inkscape:connector-curvature="0"
+ style="fill:#ff6600" />
+ </g>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="60"
+ height="60"
+ viewBox="0 0 60 60"
+ id="svg6957"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="rotate.svg"
+ style="fill:#000000"
+ inkscape:export-filename="/tmp/rotate.png"
+ inkscape:export-xdpi="36"
+ inkscape:export-ydpi="36">
+ <metadata
+ id="metadata6965">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs6963" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1215"
+ inkscape:window-height="776"
+ id="namedview6961"
+ showgrid="false"
+ inkscape:zoom="10.216667"
+ inkscape:cx="12.773247"
+ inkscape:cy="30"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg6957" />
+ <path
+ d="m 54.186198,35.208333 q 0,0.162761 -0.03255,0.227865 -2.083336,8.723958 -8.723961,14.14388 Q 38.789062,55 29.869792,55 25.117187,55 20.673828,53.209635 16.230469,51.419271 12.747396,48.098958 l -4.1992189,4.199219 q -0.6184896,0.61849 -1.4648438,0.61849 -0.8463541,0 -1.4648437,-0.61849 Q 5,51.679687 5,50.833333 L 5,36.25 q 0,-0.846354 0.6184896,-1.464844 0.6184896,-0.618489 1.4648437,-0.618489 l 14.5833337,0 q 0.846354,0 1.464843,0.618489 Q 23.75,35.403646 23.75,36.25 q 0,0.846354 -0.61849,1.464844 l -4.459635,4.459635 q 2.311198,2.148438 5.240885,3.320313 2.929688,1.171875 6.08724,1.171875 4.361979,0 8.138021,-2.115886 3.776041,-2.115885 6.054687,-5.826823 0.358073,-0.553385 1.725261,-3.808593 0.260416,-0.748698 0.976562,-0.748698 l 6.25,0 q 0.423177,0 0.732422,0.309244 0.309245,0.309245 0.309245,0.732422 z M 55,9.166667 55,23.75 q 0,0.846354 -0.61849,1.464844 -0.618489,0.618489 -1.464843,0.618489 l -14.583334,0 q -0.846354,0 -1.464843,-0.618489 Q 36.25,24.596354 36.25,23.75 q 0,-0.846354 0.61849,-1.464844 l 4.492187,-4.492187 Q 36.542969,13.333333 30,13.333333 q -4.361979,0 -8.138021,2.115886 -3.776041,2.115885 -6.054687,5.826823 -0.358073,0.553385 -1.725261,3.808593 -0.260416,0.748698 -0.976562,0.748698 l -6.4778648,0 q -0.4231771,0 -0.7324219,-0.309245 -0.3092448,-0.309244 -0.3092448,-0.732421 l 0,-0.227865 Q 7.7018229,15.839844 14.375,10.419922 21.048177,5 30,5 q 4.752604,0 9.244792,1.806641 4.492187,1.80664 7.97526,5.094401 l 4.231771,-4.199219 q 0.618489,-0.61849 1.464844,-0.61849 0.846354,0 1.464843,0.61849 Q 55,8.320312 55,9.166667 z"
+ id="path6959"
+ inkscape:connector-curvature="0"
+ style="fill:#f17f49;fill-opacity:1" />
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generated by IcoMoon.io -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="512"
+ height="512"
+ viewBox="0 0 512 512"
+ id="svg3034"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="share.svg"
+ inkscape:export-filename="/home/lin/Downloads/share.png"
+ inkscape:export-xdpi="2.8125"
+ inkscape:export-ydpi="2.8125">
+ <metadata
+ id="metadata3043">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs3041" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1855"
+ inkscape:window-height="1056"
+ id="namedview3039"
+ showgrid="false"
+ inkscape:zoom="0.88769531"
+ inkscape:cx="190.6632"
+ inkscape:cy="197.22969"
+ inkscape:window-x="65"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg3034" />
+ <g
+ id="icomoon-ignore" />
+ <path
+ d="m 378.63147,335.52475 c -17.61191,0 -33.50786,7.76112 -44.85342,20.22497 L 165.69123,266.49064 c 0.51245,-3.41791 0.78622,-6.91948 0.78622,-10.49064 0,-3.57116 -0.27377,-7.07273 -0.78622,-10.48981 l 168.08682,-89.25908 c 11.34556,12.46302 27.24151,20.22414 44.85342,20.22414 34.46177,0 62.39824,-29.67019 62.39824,-66.27063 0,-36.600439 -27.93647,-66.270627 -62.39824,-66.270627 -34.46177,0 -62.39824,29.670188 -62.39824,66.270627 0,3.57116 0.27455,7.07273 0.78622,10.48981 l -168.08682,89.25991 c -11.34556,-12.46302 -27.24151,-20.22497 -44.85342,-20.22497 -34.46177,0 -62.398241,29.67102 -62.398241,66.27063 0,36.60127 27.936471,66.27063 62.398241,66.27063 17.61191,0 33.50786,-7.76112 44.85342,-20.22414 l 168.08682,89.25908 c -0.51167,3.41708 -0.78622,6.91865 -0.78622,10.48981 0,36.60127 27.93647,66.27063 62.39824,66.27063 34.46177,0 62.39824,-29.66936 62.39824,-66.27063 0,-36.59961 -27.93647,-66.27063 -62.39824,-66.27063 z"
+ id="path3037"
+ style="fill:#999999;fill-opacity:1"
+ inkscape:connector-curvature="0" />
+</svg>
--- /dev/null
+
+PrivateShareDialog QFrame#mFrame {
+ border: 0;
+}
\ No newline at end of file
--- /dev/null
+QToolButton#mDownloadTasksBtn,
+QToolButton#mServerStatusBtn
+{
+ border-style:flat;
+}
+
+/* QToolButton:hover */
+/* { */
+/* border: 1px solid #ccc; */
+/* border-radius: 4px; */
+/* background-color: rgb(255,255,255); */
+/* } */
+
+/*
+DownloadRepoDialog {
+ min-height: 400px;
+ max-height: 400px;
+}
+*/
+
+QToolButton#mAccountBtn
+{
+ margin-right: 0px;
+}
+
+
+QFrame#mFrame
+{
+ border: 0;
+}
+
+FileBrowserDialog QToolBar QToolButton#backwardButton {
+ margin-right: 0px;
+}
+
+FileBrowserDialog QToolBar QToolButton#forwardButton {
+ margin-left: 0px;
+}
+
+SyncErrorsDialog QWidget#mainWidget {
+ border : 0;
+ border-radius: 0px;
+}
--- /dev/null
+QLabel {
+ font-family: Microsoft YaHei;
+}
+
+QFrame#mFrame {
+ background-color: white;
+}
+
+RepoTreeView {
+ font-family: Microsoft YaHei;
+}
+
+FileTableView QHeaderView::section:first {
+ padding-left: 36px;
+}
+
+SyncErrorsTableView::item {
+ padding-left: 2px;
+}
--- /dev/null
+QWidget#mainWrapper {
+ min-width: 320px;
+ min-height: 583px;
+ border: 1px solid #333;
+ border-radius: 5px;
+ background: #F5F5F7;
+}
+
+QLabel {
+ font-family: Arial;
+}
+
+CloudView {
+ min-width: 300px;
+ /* max-width: 300px; */
+ min-height: 450px;
+}
+
+QToolButton#mAccountBtn
+{
+ margin: 0;
+ padding: 0;
+ border: 0;
+}
+
+QToolButton#mAccountBtn:selected,
+QToolButton#mAccountBtn:hover {
+ background: #f8f8f8;
+}
+
+CloudView QToolBar {
+ border: 0;
+ /* max-width: 290px; */
+ border-bottom: 1px solid #DCDCDE;
+}
+
+CloudView QToolBar QWidget#spacerWidget {
+ min-width: 6px;
+ max-width: 6px;
+}
+
+QToolBar QAbstractButton {
+ margin-left: 10px;
+}
+
+RepoDetailDialog {
+ min-width: 400px;
+ min-height: 250px;
+}
+
+CloudView QLabel#mEmail {
+ font-family: Arial;
+ font-size: 15px;
+ color: #525252;
+}
+
+CloudView QLabel#mServerAddr {
+ font-family: Arial;
+ color: #A4A4A4;
+ font-size: 13px;
+}
+
+QDialog QLabel#mTitle {
+ color: #F89A01;
+ font-family: Arial;
+ font-size: 20px;
+}
+
+QToolButton#mSeahubMessagesBtn:selected,
+QToolButton#mSeahubMessagesBtn:hover {
+ background: white;
+}
+
+QWidget#mHeader {
+ min-height: 26px;
+ max-height: 26px;
+}
+
+QWidget#mHeader QPushButton {
+ padding: 5px;
+ padding-bottom: 0;
+ border: 0;
+ qproperty-focusPolicy: NoFocus;
+}
+
+QWidget#mHeader QPushButton:hover {
+ color: #FF9A2A;
+ padding-top: 3px;
+ margin-top: 1px;
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #A1A1A2,
+ stop: 1 #F5F5F7);
+}
+
+QWidget#mHeader QPushButton#mCloseBtn:hover {
+ border-top-right-radius: 5px;
+ background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
+ stop: 0 #FF9A2A,
+ stop: 1 #FEEAEA);
+}
+
+QWidget#mHeader QLabel#mBrand,
+QWidget#mHeader QLabel#mLogo {
+ margin-top: 6px;
+ margin-right: 4px;
+ font-size: 14px;
+ font-family: Arial;
+}
+
+RepoTreeView
+{
+ background: white;
+ border: 0;
+ font-size: 14px;
+ /* border-top: 1px solid #DCDCDE; */
+ /* border-bottom: 1px solid #DCDCDE; */
+ padding-top: 8px;
+}
+
+QLineEdit#mSearchBar {
+ min-height: 30px;
+ max-height: 30px;
+ margin-left: 16px;
+ margin-right: 16px;
+ margin-top: 0;
+ margin-bottom: 0px;
+ padding: 0 0px;
+ border: 1px solid #E0E0E0;
+ border-radius: 3px;
+}
+
+QLineEdit#mSearchBar QLabel {
+ text-align: center;
+ margin-left: 16px;
+ margin-right: 16px;
+}
+
+QLineEdit#mSearchBar:focus {
+ color: #525252;
+}
+
+
+RepoTreeView QScrollBar {
+ margin-right: 1px;
+}
+
+CloudView QWidget#mDropArea {
+ min-height: 54px;
+ max-height: 54px;
+ background: #F9F9F9;
+ padding: 0;
+ padding-top: 10px;
+}
+
+CloudView QFrame#mDropInner {
+ min-width: 280px;
+ /* max-width: 280px; */
+ min-height: 50px;
+ max-height: 50px;
+ border: 1.5px dashed #E4E4E4;
+ border-radius: 3px;
+ padding: 0px 0;
+}
+
+CloudView QFrame#mDropInner QLabel {
+ font-family: Arial;
+}
+
+CloudView QPushButton#mSelectFolderBtn {
+ min-height: 26px;
+ max-height: 26px;
+ font-size: 14px;
+ font-family: Arial;
+ border: 1px solid #C5C5C5;
+ border-radius: 3px;
+ color: #4A4A4A;
+ background: #F5F5F7;
+ qproperty-focusPolicy: NoFocus;
+ qproperty-flat: true;
+ padding-right: 15px;
+ padding-left: 15px;
+ margin: 0;
+}
+
+CloudView QPushButton#mSelectFolderBtn:hover {
+ font-size: 14px;
+ font-weight: ;
+ background: #DBDBDC;
+ border-radius: 3px;
+}
+
+CloudView QLabel#mDropFolderText {
+ color: #888888;
+ font-size: 14px;
+ margin-left: 3px;
+}
+
+CloudView QFrame#mFooter {
+ border: 0;
+ min-height: 28px;
+ max-height: 28px;
+ margin-bottom: 2px;
+ padding: 0;
+ padding-bottom: 0px;
+ padding-right: 0px;
+ background: #F9F9F9;
+}
+
+CloudView QFrame#mFooter QLabel#mDownloadTasksInfo,
+CloudView QFrame#mFooter QLabel#mDownloadRate,
+CloudView QFrame#mFooter QLabel#mUploadRate
+{
+ color: #999999;
+ font-size: 10px;
+ min-height: 14px;
+ max-height: 14px;
+ margin-bottom: 0px;
+ min-width: 50px;
+ /* max-width: 80px; */
+}
+
+CloudView QFrame#mFooter QLabel#mUploadRateArrow,
+CloudView QFrame#mFooter QLabel#mDownloadRateArrow
+{
+ min-height: 10px;
+ max-height: 10px;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ margin-right: 0px;
+ margin-left: 5px;
+}
+
+CloudView QFrame#mFooter QLabel#mDownloadRateArrow
+{
+ margin-right: 0px;
+}
+
+
+CreateRepoDialog {
+ min-width: 550px;
+ min-height: 247px;
+ max-height: 247px;
+}
+
+CreateRepoDialog QLabel#mDesc {
+ min-height: 60px;
+}
+
+QFrame#mFooter QToolButton#mServerStatusBtn,
+QFrame#mFooter QToolButton#mDownloadTasksBtn {
+ margin-top: 0px;
+ qproperty-focusPolicy: NoFocus;
+}
+
+QFrame#mFooter QToolButton#mServerStatusBtn {
+ margin-left: 10px;
+ alignment: left;
+}
+
+ServerStatusDialog QListView {
+ qproperty-focusPolicy: NoFocus;
+}
+
+ServerStatusDialog QListView:item {
+ margin-bottom: 4px;
+}
+
+UninstallHelperDialog {
+ min-width: 400px;
+ /* max-width: 400px; */
+ min-height: 100px;
+ max-height: 100px;
+}
+
+CloudView QSizeGrip {
+ margin-right: 2px;
+}
+
+InitVirtualDriveDialog QLabel#mStatusText {
+ font-size: 16px;
+ font-family: Arial;
+ padding-right: 20px;
+ qproperty-wordWrap: true;
+ min-width: 350px;
+}
+
+InitVirtualDriveDialog QLabel#mStatusIcon {
+ min-width: 48px;
+ max-width: 48px;
+ margin-left: 60px;
+ margin-right: 20px;
+}
+
+QLabel#loadingFailedText {
+ color: #777;
+ font-size: 16px;
+ margin-top: -120px;
+ qproperty-wordWrap: true;
+}
+
+SettingsDialog {
+ min-width: 560px;
+ max-width: 560px;
+
+ min-height: 390px;
+ max-height: 390px;
+}
+
+SettingsDialog QTabWidget::pane QLabel#desc,
+SettingsDialog QTabWidget::pane QLabel#desc_2
+{
+ font-size: 12px;
+ color: #555;
+ padding-left: 20px;
+}
+
+LoginDialog QLabel#hint,
+LoginDialog QLabel#hint_1,
+LoginDialog QLabel#hint_2,
+LoginDialog QLabel#hint_3
+{
+ font-size: 12px;
+ color: #555;
+}
+
+ShibLoginDialog QLineEdit#addressText {
+ min-height: 25px;
+ margin: 0px;
+ padding: 0 4px;
+ border: 1px solid #BCBCBE;
+ border-radius: 3px;
+}
+
+SslConfirmDialog {
+ min-width: 400px;
+ min-height: 200px;
+}
+
+SslConfirmDialog QLabel#mHint {
+ margin-right: 20px;
+}
+
+SslConfirmDialog QCheckBox#mRememberChoiceCheckBox {
+ min-height: 40px;
+ max-height: 40px;
+ margin-bottom: 5px;
+ /* border: 1px solid black; */
+}
+
+DownloadRepoDialog QLabel#mRepoName {
+ font-size: 16px;
+ margin-bottom: 8px;
+}
+
+DownloadRepoDialog QLabel#mMergeHint {
+ font-size: 12px;
+}
+
+DownloadRepoDialog QLabel#mRepoIcon {
+ min-width: 36px;
+ max-width: 36px;
+ min-height: 36px;
+ max-height: 36px;
+ margin-right: 10px;
+ margin-bottom: 8px;
+}
+
+DownloadRepoDialog QPushButton#mSwitchToSyncBtn {
+}
+
+SeafileTabWidget {
+ border: 0;
+ margin: 0;
+}
+
+SeafileTabBar {
+ alignment: left;
+ border: 0;
+}
+
+SeafileTabBar::tab {
+ background: white;
+
+ min-height: 36px;
+ max-height: 36px;
+
+ min-width: 100px;
+
+ padding: 0;
+ border: 0;
+}
+
+StarredFilesListView {
+ border-top: 1px solid #DCDCDE;
+}
+
+QWidget#EmptyPlaceHolder,
+LoadingView
+{
+ border-top: 1px solid #DCDCDE;
+}
+
+QWidget#EventsContainerView {
+ margin: 0;
+ border: 0;
+ border-top: 1px solid #DCDCDE;
+}
+
+QWidget#EventsContainerView LoadingView,
+QWidget#EventsContainerView QToolButton
+{
+ max-height: 40px;
+ min-height: 40px;
+}
+
+QWidget#EventsContainerView LoadingView {
+ /* border: 1px solid red; */
+ border: 0;
+ background: white;
+ margin: 0;
+}
+
+EventsListView {
+ border: 0;
+ border-top: 1px solid #DCDCDE;
+}
+
+EventDetailsDialog {
+ margin: 20px;
+ min-width: 300px;
+ min-height: 300px;
+}
+
+EventDetailsListView
+{
+ background: white;
+ border: 0;
+ font-size: 16px;
+ border-top: 1px solid #DCDCDE;
+}
+
+EventDetailsListView {
+ qproperty-iconSize: 36px;
+}
+
+EventDetailsListView QScrollBar {
+ margin-right: 1px;
+}
+
+ActivitiesTab, EventsListView
+{
+ qproperty-focusPolicy: NoFocus;
+}
+
+FileBrowserDialog {
+ margin: 0;
+ min-width: 640px;
+ min-height: 456px;
+}
+
+FileBrowserDialog QToolBar#topBar {
+ border: 0;
+ border-bottom: 1px solid #d0d0d0;
+ padding: 0;
+ min-height: 42px;
+ background: #F5F5F7;
+ spacing: 0;
+}
+
+FileBrowserDialog QToolBar QPushButton {
+ font-size: 13px;
+ padding: 3px;
+ margin: 1px;
+ background-color: white;
+ qproperty-focusPolicy: NoFocus;
+}
+
+FileBrowserDialog QToolBar QWidget#goHomeButton {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ padding-left: 3px;
+ margin-right: -7px;
+}
+
+FileBrowserDialog QToolBar QToolButton#backwardButton {
+ border: 0;
+}
+
+FileBrowserDialog QToolBar QToolButton#forwardButton {
+ border: 0;
+}
+
+FileBrowserDialog QToolBar QLabel {
+ margin-left: 2px;
+}
+
+FileBrowserDialog QToolBar QPushButton:hover {
+ border: 1px solid #d0d0d0;
+ border-radius: 4px;
+ color: #FF9A2A;
+}
+
+FileTableView {
+ border: 0;
+ margin: 0;
+ padding-left: 0px;
+ border-bottom: 1px solid #e0e0e0;
+ background-color: white;
+ qproperty-focusPolicy: NoFocus;
+}
+
+FileTableView QHeaderView::section,
+FileBrowserSearchView QHeaderView::section{
+ border: 0;
+ padding: 8px;
+ outline: 0px;
+ color: #b3b3b3;
+ background-color: white;
+ font-size: 12px;
+ padding-top: 20px;
+}
+
+FileTableView QHeaderView::section:first,
+FileBrowserSearchView QHeaderView::section:first{
+ padding-left: 40px;
+}
+
+FileTableView QHeaderView::down-arrow,
+FileBrowserSearchView QHeaderView::down-arrow{
+ width: 15px;
+ height: 5px;
+ padding-top: 15px;
+ subcontrol-position: center right;
+}
+
+FileTableView QHeaderView::up-arrow,
+FileBrowserSearchView QHeaderView::up-arrow{
+ padding-top: 15px;
+ subcontrol-position: center right;
+}
+
+FileTableView QHeaderView::down-arrow,
+FileBrowserSearchView QHeaderView::down-arrow{
+ image: url(:/images/filebrowser/down-arrow.png);
+}
+
+FileTableView QHeaderView::up-arrow,
+FileBrowserSearchView QHeaderView::up-arrow{
+ image: url(:/images/filebrowser/up-arrow.png);
+}
+
+FileTableView::item,
+FileBrowserSearchView::item{
+ border-top: 1px solid #e0e0e0;
+}
+
+FileTableView::item :last,
+FileBrowserSearchView::item :last{
+ padding-right: 13px;
+}
+
+FileBrowserDialog QWidget#statusBar {
+ padding: 0px;
+ margin: 0px;
+ min-height: 36px;
+ max-height: 36px;
+ background: #F5F5F7;
+}
+
+FileBrowserDialog QToolButton#uploadButton {
+ border: 0;
+ padding: 0px;
+ margin-left: 15px;
+}
+
+FileBrowserDialog QToolButton#refreshButton {
+ border: 0;
+ margin-right: 15px;
+}
+
+FileBrowserProgressDialog {
+ min-width: 320px;
+ max-width: 420px;
+}
+
+SeafileTabWidget QWidget#pane {
+ background-color: white;
+}
+
+SharedLinkDialog QLabel {
+ font-size: 12px;
+}
+
+SharedLinkDialog QCheckBox {
+ font-size: 10px;
+}
+
+SeafileLinkDialog QLabel {
+ font-size: 12px;
+}
+
+SeafileLinkDialog QCheckBox {
+ font-size: 10px;
+}
+
+SearchResultListView {
+ border-top: 1px solid #DCDCDE;
+ border-bottom: 1px solid #DCDCDE;
+}
+
+QProgressBar#mStorageUsage {
+ min-width: 60px;
+ max-width: 60px;
+ max-height: 6px;
+ min-height: 6px;
+ border: 1px solid #DBDBDC;
+ border-radius: 1px;
+ text-align: right;
+ margin-top: 0px;
+ margin-left: 0px;
+ margin-right: 0;
+ font-size: 11px;
+}
+
+PrivateShareDialog {
+ min-width: 550px;
+ min-height: 200px;
+}
+
+/* PrivateShareDialog QLabel#mStatusText { */
+/* padding-left: 1px; */
+/* } */
+
+PrivateShareDialog QLineEdit#mUsernameInputBar {
+ padding-left: 4px;
+}
+
+SharedItemsTableView {
+ margin-top: 10px;
+ qproperty-focusPolicy: NoFocus;
+}
+
+SharedItemsTableView QHeaderView::section {
+ /* outline: 1px; */
+ font-size: 12px;
+ padding-top: 10px;
+ font-family: Arial;
+}
+
+SyncErrorsDialog {
+ margin: 0;
+ min-width: 700px;
+ min-height: 300px;
+}
+
+SyncErrorsTableView {
+ border: 0;
+ margin: 0;
+ padding-left: 14px;
+ padding-right: 14px;
+ border-bottom: 1px solid #e0e0e0;
+ background-color: white;
+ qproperty-focusPolicy: NoFocus;
+}
+
+SyncErrorsTableView QHeaderView::section {
+ border: 0;
+ padding: 8px;
+ padding-left: 5px;
+ outline: 0px;
+ color: #b3b3b3;
+ background-color: white;
+ font-size: 12px;
+ padding-top: 20px;
+}
+
+SyncErrorsTableView::item {
+ padding-top: 5px;
+ padding-left: 0px;
+ border-top: 1px solid #e0e0e0;
+}
+
+SyncErrorsTableView::item :last {
+ padding-right: 13px;
+}
+
+SyncErrorsTableView::item:selected {
+ background-color: #F9E0C7;
+}
+
+LoadMoreButton QToolButton#loadMoreBtn {
+ padding: 0;
+ font-family: Arial;
+ font-size: 14px;
+ qproperty-focusPolicy: NoFocus;
+ /* text-decoration: underline; */
+ color: #626262;
+ border: 0;
+ border-radius: 18px;
+ /* border-top: 1px solid #eee; */
+ background-color: #EFEEEE;
+ width: 120px;
+ height: 34px;
+}
+
+SeafileTabWidget QToolButton:hover {
+ border: 0;
+ border-radius: 0;
+}
--- /dev/null
+#!/usr/bin/env python
+import sys, os, shutil
+import build_helper
+import argparse
+
+target='seafile-applet'
+num_cpus=str(build_helper.num_cpus)
+configuration = 'Release'
+
+def postbuild_copy_libraries():
+ print 'copying dependent libraries...'
+ if sys.platform == 'darwin':
+ postbuild_copy_libraries_xcode()
+ else:
+ postbuild_copy_libraries_posix()
+
+def postbuild_copy_libraries_posix():
+ lib_path = os.path.join(target, 'lib')
+ bin_path = os.path.join(target, 'bin')
+ binaries = [os.path.join(bin_path, target),
+ os.path.join(bin_path, 'ccnet'),
+ os.path.join(bin_path, 'seaf-daemon')]
+ libs = []
+ for binrary in binaries:
+ libs.extend(build_helper.get_dependencies_recursively(binrary))
+ if not os.path.isdir(lib_path):
+ os.makedirs(lib_path)
+ for lib in libs:
+ shutil.copyfile(lib, lib_path + '/' + os.path.basename(lib))
+
+def postbuild_copy_libraries_xcode():
+ frameworks_path = os.path.join(target + '.app', 'Contents', 'Frameworks')
+ resources_path = os.path.join(target + '.app', 'Contents', 'Resources')
+ macos_path = os.path.join(target + '.app', 'Contents', 'MacOS')
+ binaries = [os.path.join(macos_path, target),
+ os.path.join(resources_path, 'ccnet'),
+ os.path.join(resources_path, 'seaf-daemon')]
+ libs = []
+ for binrary in binaries:
+ libs.extend(build_helper.get_dependencies_recursively(binrary))
+ if not os.path.isdir(frameworks_path):
+ os.makedirs(frameworks_path)
+ for lib in libs:
+ shutil.copyfile(lib, frameworks_path + '/' + os.path.basename(lib))
+ build_helper.write_output(['macdeployqt', target + '.app'])
+
+def postbuild_fix_rpath():
+ print 'fixing rpath...'
+ if os.name == 'winnt':
+ print 'not need to fix rpath'
+ elif sys.platform == 'linux':
+ postbuild_patchelf()
+ elif sys.platform == 'darwin':
+ postbuild_install_name_tool()
+ else:
+ print 'not supported in platform %s' % sys.platform
+ print 'fixing rpath...done'
+
+def postbuild_install_name_tool():
+ frameworks_path = os.path.join(target + '.app', 'Contents', 'Frameworks')
+ resources_path = os.path.join(target + '.app', 'Contents', 'Resources')
+ macos_path = os.path.join(target + '.app', 'Contents', 'MacOS')
+ binaries = [os.path.join(macos_path, target),
+ os.path.join(resources_path, 'ccnet'),
+ os.path.join(resources_path, 'seaf-daemon')]
+ for binary in binaries:
+ build_helper.write_output(['install_name_tool', '-add_rpath', '@executable_path/../Frameworks', binary])
+ deps = build_helper.get_dependencies(binary)
+ for dep in deps:
+ build_helper.write_output(['install_name_tool', '-change', dep, '@executable_path/../Frameworks/%s' % os.path.basename(dep), binary])
+ build_helper.write_output(['install_name_tool', '-delete_rpath', '/usr/local/lib', binary])
+ build_helper.write_output(['install_name_tool', '-delete_rpath', '/opt/local/lib', binary])
+ libs = os.listdir(frameworks_path)
+ for lib_name in libs:
+ lib = os.path.join(frameworks_path, lib_name)
+ if os.path.isdir(lib):
+ continue
+ build_helper.write_output(['install_name_tool', '-id', '@loader_path/../Frameworks/%s' % os.path.basename(lib), lib])
+ build_helper.write_output(['install_name_tool', '-add_rpath', '@loader_path/../Frameworks', lib])
+ build_helper.write_output(['install_name_tool', '-delete_rpath', '/usr/local/lib', lib])
+ build_helper.write_output(['install_name_tool', '-delete_rpath', '/opt/local/lib', lib])
+ deps = build_helper.get_dependencies(lib)
+ for dep in deps:
+ build_helper.write_output(['install_name_tool', '-change', dep, '@loader_path/../Frameworks/%s' % os.path.basename(dep), lib])
+
+def postbuild_patchelf():
+ lib_path = os.path.join(target, 'lib')
+ bin_path = os.path.join(target, 'bin')
+ binaries = os.listdir(bin_path)
+ for binrary_name in binaries:
+ binrary = os.path.join(bin_path, binrary_name)
+ if os.path.isdir(binrary):
+ continue
+ build_helper.write_output(['patchelf', '-set-rpath', '\\\$ORIGIN/../lib', binrary])
+ libs = os.listdir(lib_path)
+ for lib_name in libs:
+ lib = os.path.join(lib_path, lib_name)
+ if os.path.isdir(lib):
+ continue
+ build_helper.write_output(['patchelf', '-set-rpath', '\\\$ORIGIN/../lib', lib])
+
+def execute_buildscript(generator = 'xcode'):
+ print 'executing build scripts...'
+ if generator == 'xcode':
+ command = ['xcodebuild', '-target', 'ALL_BUILD', '-configuration', configuration, '-jobs', num_cpus]
+ elif generator == 'ninja':
+ command = ['ninja']
+ else:
+ command = ['make', '-j', num_cpus]
+ build_helper.write_output(command)
+ if generator == 'xcode':
+ shutil.copytree(os.path.join(configuration, target+ '.app'), target + '.app')
+
+
+def generate_buildscript(generator = 'xcode', os_min = '10.7', with_shibboleth = False):
+ print 'generating build scripts...'
+ if not os.path.exists('CMakeLists.txt'):
+ print 'Please execute this frome the top dir of the source'
+ sys.exit(-1)
+ cmake_args = ['cmake', '.', '-DCMAKE_BUILD_TYPE=' + configuration]
+ cmake_args.append('-DCMAKE_OSX_DEPLOYMENT_TARGET=' + os_min);
+ if with_shibboleth:
+ cmake_args.append('-DBUILD_SHIBBOLETH_SUPPORT=ON')
+ else:
+ cmake_args.append('-DBUILD_SHIBBOLETH_SUPPORT=OFF')
+ if generator == 'xcode':
+ cmake_args.extend(['-G', 'Xcode'])
+ elif generator == 'ninja':
+ cmake_args.extend(['-G', 'Ninja'])
+ else:
+ cmake_args.extend(['-G', 'Unix Makefiles'])
+ build_helper.write_output(cmake_args)
+
+def prebuild_cleanup(Force=False):
+ print 'cleaning up previous files...'
+ if Force:
+ build_helper.write_output(['git', 'clean', '-xfd'])
+ return
+ shutil.rmtree(configuration, ignore_errors=True)
+ shutil.rmtree('CMakeFiles', ignore_errors=True)
+ shutil.rmtree(target+ '.app', ignore_errors=True)
+ if os.path.exists ('CMakeCache.txt'):
+ os.remove('CMakeCache.txt')
+
+if __name__ == '__main__':
+ if sys.platform != 'darwin':
+ print 'Only support Mac OS X Platfrom!'
+ exit(-1)
+
+ parser = argparse.ArgumentParser(description='Script to build Seafile Client and package it')
+ parser.add_argument('--build_type', '-t', help='build type', default='Release')
+ parser.add_argument('--os_min', '-m', help='osx deploy version', default='10.7')
+ parser.add_argument('--with_shibboleth', help='build with shibboleth support', action='store_true')
+ parser.add_argument('--output', '-o', help='output file', default='-')
+ parser.add_argument('--clean', '-c', help='clean forcely', action='store_true')
+ args = parser.parse_args()
+
+ if args.build_type == 'Debug' or args.build_type == 'debug':
+ configuration = 'Debug'
+
+ print 'build with type %s' % configuration
+
+ os.chdir(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
+
+ prebuild_cleanup(Force=args.clean)
+
+ if args.output == '-':
+ build_helper.set_output(sys.stdout)
+ else:
+ output = open(args.output, 'wb')
+ build_helper.set_output(output)
+
+ generate_buildscript(os_min=args.os_min, with_shibboleth=args.with_shibboleth)
+ execute_buildscript()
+ postbuild_copy_libraries()
+ postbuild_fix_rpath()
+
+ build_helper.close_output()
--- /dev/null
+#!/usr/bin/env bash
+
+set -e
+
+PWD=$(dirname "${BASH_SOURCE[0]}")
+
+## get a copy of breakpad if not exist
+if [ ! -d $PWD/../third_party/breakpad ]; then
+ pushd $PWD/../third_party
+ git clone https://github.com/Chilledheart/breakpad.git
+ popd
+fi
+
+## get a copy of gyp if not exist
+if [ ! -d $PWD/../third_party/gyp ]; then
+ pushd $PWD/../third_party
+ git clone https://chromium.googlesource.com/external/gyp.git
+ popd
+fi
+
+## build breakpad
+pushd $PWD/../third_party/breakpad
+
+GYP_GENERATORS=ninja ../gyp/gyp --depth .
+if [ -d out/Debug_Base ]; then
+ ninja -C out/Debug_Base
+elif [ -d out/Default ]; then
+ ninja -C out/Default
+else
+ echo "unable to find build.ninja, exiting"
+fi
+
+echo "breakpad was built successfuly"
+echo "now you can set up your PATH_TO_BREAKPAD_ROOT to $(pwd)"
+
+popd
+
+
--- /dev/null
+#!/usr/bin/env python
+import subprocess, sys, os
+import re
+from multiprocessing import cpu_count
+
+num_cpus=cpu_count()
+
+def get_dependencies_by_otool(path):
+ if path.endswith('.app') and os.path.isdir(path):
+ path = os.path.join(path, 'Contents', 'MacOS', os.path.basename(path))
+ lines = check_string_output(['otool', '-L', path]).split('\n')[1:]
+ outputs = []
+ if path.endswith('.dylib'):
+ outputs.append(path);
+
+ for line in lines:
+ name = line.split('(')[0].strip()
+ if name.startswith('@executable_path/'):
+ name = os.path.join(path, name[len('@executable_path/'):])
+ if name.startswith('@loader_path/'):
+ name = os.path.join(path, name[len('@loader_path/'):])
+ # todo: search rpath
+ if not name.startswith('/'):
+ continue
+ # skip system libraries
+ if name.startswith('/usr/lib') or name.startswith('/System'):
+ continue
+ # skip Frameworks (TODO: support frameworks, except Qt's framewroks)
+ if re.search(r'(\w+)\.framework/Versions/[A-Z0-9]/(\1)$', name):
+ continue
+ # if file not found
+ if not os.path.exists(name):
+ raise IOError('broken dependency: file %s not found' % name)
+ outputs.append(os.path.normpath(name))
+
+ return outputs
+
+def get_dependencies_by_ldd(path):
+ lines = check_string_output(['ldd', '-v', path]).split('Version information:')[1].split('\n\t')
+ outputs = []
+
+ for line in lines:
+ if not line.startswith('\t'):
+ continue
+ name = line.strip().split('=>')[1].strip()
+ # todo: search rpath
+ if name.startswith('$ORIGIN/'):
+ name = os.path.join(path, name[len('$ORIGIN/'):])
+ # skip system libraries, such as linux-vdso.so
+ if not name.startswith('/'):
+ continue
+ # skip system libraries, part2
+ if name.startswith('/usr/lib') or name.startswith('/usr/lib64'):
+ continue
+ # skip system libraries, part3
+ if name.startswith('/lib') or name.startswith('/lib64'):
+ continue
+ # if file not found
+ if not os.path.exists(name):
+ raise IOError('broken dependency: file %s not found' % name)
+ outputs.append(os.path.normpath(name))
+
+ # remove duplicate items
+ return list(set(outputs))
+
+def get_dependencies_by_objdump(path):
+ print 'todo'
+ return []
+
+def get_dependencies_by_dependency_walker(path):
+ print 'todo'
+ return []
+
+def get_dependencies(path):
+ if os.name == 'winnt':
+ return get_dependencies_by_objdump(path)
+ elif sys.platform == 'darwin':
+ return get_dependencies_by_otool(path)
+ elif sys.platform == 'linux':
+ return get_dependencies_by_ldd(path)
+ else:
+ raise IOError('not supported in platform %s' % sys.platform)
+
+def get_dependencies_recursively(path):
+ if os.name == 'winnt':
+ return get_dependencies_by_objdump(path)
+ elif sys.platform == 'darwin':
+ deps = get_dependencies_by_otool(path)
+ while(True):
+ deps_extened = list(deps)
+ for dep in deps:
+ deps_extened.extend(get_dependencies_by_otool(dep))
+ deps_extened = set(deps_extened)
+ if deps_extened != deps:
+ deps = deps_extened;
+ else:
+ return list(deps_extened)
+ elif sys.platform == 'linux':
+ return get_dependencies_by_ldd(path)
+ else:
+ raise IOError('not supported in platform %s' % sys.platform)
+
+def check_string_output(command):
+ return subprocess.check_output(command, stderr=subprocess.STDOUT).decode().strip()
+
+_output = sys.stdout
+def set_output(output=sys.stdout):
+ global _output
+ _output = output
+
+def close_output():
+ if _output != sys.stdout:
+ _output.close()
+
+def write_output(command):
+ proc = subprocess.Popen(command, stdout=_output, stderr=_output, shell=False)
+ proc.communicate()
+
+if __name__ == '__main__':
+ if (len(sys.argv) < 2):
+ print 'Usage: %s <input-file>' % sys.argv[0]
+ sys.exit(-1)
+ print get_dependencies_recursively(sys.argv[1])
--- /dev/null
+#!/bin/bash
+set -x
+set -e
+PWD=$(dirname "${BASH_SOURCE[0]}")
+
+pushd $PWD/..
+
+if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+ set +e
+ . /opt/qt56/bin/qt56-env.sh
+ set -e
+ cmake -DBUILD_TESTING=on -DBUILD_SHIBBOLETH_SUPPORT=$BUILD_SHIBBOLETH_SUPPORT .
+ make -j8 VERBOSE=1
+ make test VERBOSE=1
+elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
+ export PATH=/usr/local/opt/openssl/bin:/usr/local/opt/curl/bin:$PATH
+ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/usr/local/opt/curl/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig:/usr/local/opt/openssl/lib/pkgconfig:/usr/local/opt/sqlite/lib/pkgconfig
+ export CPPFLAGS="-I/usr/local/opt/openssl/include -I/usr/local/opt/sqlite/include -I/usr/local/opt/curl/include"
+ export CXXFLAGS="$CXXFLAGS $CPPFLAGS -I/usr/local/include"
+ export LDFLAGS="-L/usr/local/opt/openssl/lib -L/usr/local/opt/sqlite/lib -L/usr/local/opt/curl/lib -L/usr/local/lib"
+ export PKG_CONFIG_LIBDIR=/usr/lib/pkgconfig:/usr/local/Library/ENV/pkgconfig/10.9
+ export ACLOCAL_PATH=/usr/local/share/aclocal
+ cmake -G Xcode -DBUILD_TESTING=on .
+ xcodebuild -configuration Debug -target ALL_BUILD -jobs 8
+ xcodebuild -configuration Debug -target RUN_TESTS
+else
+ printf "not supported platform"
+ exit -1
+fi
+
+popd
--- /dev/null
+#!/bin/sh
+
+set -e
+
+build_file="build.py"
+
+print "WARNING: this file is deprecated."
+print "Please use $build_file instead"
+
+"$build_file" "$@"
--- /dev/null
+#!/bin/bash
+set -x
+set -e
+PWD=$(dirname "${BASH_SOURCE[0]}")
+
+SEAFILE_BRANCH=master
+
+# Temporary fix
+sudo sed -i /rabbitmq\.com/d /etc/apt/sources.list
+sudo sed -i /rabbitmq\.com/d /etc/apt/sources.list.d/*.list
+
+sudo add-apt-repository -y ppa:smspillaz/cmake-2.8.12
+sudo apt-get update -qq
+sudo apt-get install -y valac uuid-dev libevent-dev re2c libjansson-dev cmake cmake-data
+
+sudo add-apt-repository -y ppa:beineri/opt-qt562-trusty
+sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+sudo apt-get update -qq
+
+sudo apt-get install -y gcc-4.8 g++-4.8
+sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 50
+sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.8 50
+
+sudo apt-get install -y qt56base qt56translations qt56tools qt56webengine
+
+# Fix errors like:
+#
+# CMake Error at /opt/qt56/lib/cmake/Qt5Gui/Qt5GuiConfigExtras.cmake:9 (message):
+# Failed to find "GL/gl.h" in "/usr/include/libdrm"
+#
+# See https://github.com/Studio3T/robomongo/issues/1268
+sudo apt-get install -y mesa-common-dev libglu1-mesa-dev
+
+git clone --depth=1 --branch=master git://github.com/haiwen/libsearpc.git deps/libsearpc
+git clone --depth=1 --branch=master git://github.com/haiwen/ccnet.git deps/ccnet
+git clone --depth=1 --branch="$SEAFILE_BRANCH" git://github.com/haiwen/seafile.git deps/seafile
+pushd deps/libsearpc
+./autogen.sh && ./configure
+make -j8 && sudo make install
+popd
+
+pushd deps/ccnet
+./autogen.sh && ./configure --enable-client --disable-server
+make -j8 && sudo make install
+popd
+
+pushd deps/seafile
+./autogen.sh && ./configure --disable-fuse --disable-server --enable-client
+make -j8 && sudo make install
+popd
--- /dev/null
+#!/bin/bash
+set -x
+set -e
+## TODO: use the correct version of seafile for each branch
+
+brew up
+brew install qt4
+
+brew tap Chilledheart/seafile
+brew install --HEAD libsearpc ccnet seafile
--- /dev/null
+#!/bin/bash
+
+# Strip profiles and comments from png files.
+# This can avoid libpng warnings.
+# See https://wiki.archlinux.org/index.php/Libpng_errors
+
+[[ -x `which convert` ]] || {
+ echo
+ echo "Please install ImageMagick tool first".
+ echo
+ echo "On ubuntu: apt-get install imagemagick"
+ echo "On macos: port install ImageMagick"
+ echo
+}
+
+TOP_DIR=$(python -c "import os; print os.path.dirname(os.path.realpath('$0'))")/..
+
+find $TOP_DIR -type f -name \*.png -exec convert -strip {} {} \;
--- /dev/null
+#!/usr/bin/env bash
+set -e
+
+PWD=$(dirname "${BASH_SOURCE[0]}")
+cd $PWD/..
+
+if [ ! -d .tx ]; then
+ echo "please make sure this script is under the scripts directory!"
+ exit -9
+fi
+
+if [ "$1" != "-v" ]; then
+ QUIET_FLAGS="-silent"
+fi
+
+function regenerate_source() {
+ if [ -f build.ninja ]; then
+ cmake -DBUILD_SHIBBOLETH_SUPPORT=on
+ ninja update-ts
+ elif [ -f Makefile ]; then
+ cmake -DBUILD_SHIBBOLETH_SUPPORT=on
+ make update-ts
+ else
+ local SEAFILE_PROJECT="seafile-client.pro"
+ rm -f $SEAFILE_PROJECT
+ qmake -project -o $SEAFILE_PROJECT
+ lrelease $SEAFILE_PROJECT $QUIET_FLAGS
+ lupdate $SEAFILE_PROJECT $QUIET_FLAGS
+ rm -f $SEAFILE_PROJECT
+ fi
+ find fsplugin -name "*.mm" | xargs genstrings -o fsplugin/en.lproj
+}
+
+function git_diff() {
+ set +e
+ git diff i18n/seafile_en.ts fsplugin/en.lproj
+ set -e
+}
+
+function push_source() {
+ tx push -s
+ pushd fsplugin
+ tx push -s
+ popd
+}
+
+function pull_translations() {
+ tx pull -a -f --minimum-perc=30
+ pushd fsplugin
+ tx pull -a -f --minimum-perc=80
+ popd
+}
+
+echo "This script will help you to regenerate sources of translations, "
+echo "update them to transifex and grab the latest translations from it"
+echo
+echo "========================================================================="
+echo
+echo " Make sure you have review the source difference beforce pushing!"
+echo " Press Control+C once you want to abort this script"
+echo
+echo "========================================================================="
+echo
+
+echo "[0/4] Press any key to start"
+read -s -n 1
+echo "[1/4] Regenerating sources files"
+regenerate_source
+echo "[1/4] Regenerating sources files"
+
+echo "[2/4] Press any key to view diff"
+read -s -n 1
+git_diff
+
+echo "[3/4] Press any key to push source to transifix"
+read -s -n 1
+push_source
+
+echo "[4/4] Press any key to pull translations"
+read -s -n 1
+pull_translations
+echo "[4/4] All Done"
--- /dev/null
+#include <winver.h>
+#define RC_VERSION ${SEAFILE_CLIENT_VERSION_MAJOR}, ${SEAFILE_CLIENT_VERSION_MINOR}, ${SEAFILE_CLIENT_VERSION_PATCH}, 0
+#define RC_VERSION_STR "${SEAFILE_CLIENT_VERSION_MAJOR}.${SEAFILE_CLIENT_VERSION_MINOR}.${SEAFILE_CLIENT_VERSION_PATCH}.0\0"
+LANGUAGE 0x09,0x01
+1 24 DISCARDABLE Application.manifest
+2 ICON DISCARDABLE "seafile.ico"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION RC_VERSION
+ PRODUCTVERSION RC_VERSION
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Seafile Ltd.\0"
+ VALUE "FileDescription", "Seafile Client"
+ VALUE "FileVersion", RC_VERSION_STR
+ VALUE "InternalName", "seafile-applet\0"
+ VALUE "OriginalFilename", "seafile-applet.exe\0"
+ VALUE "LegalCopyright", "2015 Seafile Ltd.\0"
+ VALUE "ProductName", "Seafile Client\0"
+ VALUE "ProductVersion", RC_VERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
--- /dev/null
+<RCC>
+<qresource>
+ <file>images/seafile.png</file>
+ <file>images/seafile-24.png</file>
+ <file>images/seafile-32.png</file>
+ <file>images/account.png</file>
+ <file>images/account@2x.png</file>
+ <file>images/folder.png</file>
+ <file>images/loading-spinner.gif</file>
+ <file>images/daemon_up.png</file>
+ <file>images/daemon_down.png</file>
+ <file>images/seafile_auto_sync_disabled.png</file>
+ <file>images/seafile_transfer_1.png</file>
+ <file>images/seafile_transfer_2.png</file>
+ <file>images/seafile_warning.png</file>
+ <file>images/notification.png</file>
+ <file>images/win/daemon_up.ico</file>
+ <file>images/win/daemon_down.ico</file>
+ <file>images/win/seafile_warning.ico</file>
+ <file>images/win/seafile_auto_sync_disabled.ico</file>
+ <file>images/win/seafile_transfer_1.ico</file>
+ <file>images/win/seafile_transfer_2.ico</file>
+ <file>images/win/notification.ico</file>
+ <file>images/mac/daemon_down.png</file>
+ <file>images/mac/daemon_down@2x.png</file>
+ <file>images/mac/daemon_down_white.png</file>
+ <file>images/mac/daemon_down_white@2x.png</file>
+ <file>images/mac/daemon_up.png</file>
+ <file>images/mac/daemon_up@2x.png</file>
+ <file>images/mac/daemon_up_white.png</file>
+ <file>images/mac/daemon_up_white@2x.png</file>
+ <file>images/mac/notification.png</file>
+ <file>images/mac/notification@2x.png</file>
+ <file>images/mac/notification_white.png</file>
+ <file>images/mac/seafile_auto_sync_disabled.png</file>
+ <file>images/mac/seafile_auto_sync_disabled@2x.png</file>
+ <file>images/mac/seafile_auto_sync_disabled_white.png</file>
+ <file>images/mac/seafile_auto_sync_disabled_white@2x.png</file>
+ <file>images/mac/seafile_transfer_1.png</file>
+ <file>images/mac/seafile_transfer_1_white.png</file>
+ <file>images/mac/seafile_transfer_2.png</file>
+ <file>images/mac/seafile_transfer_2_white.png</file>
+ <file>images/mac/seafile_warning.png</file>
+ <file>images/mac/seafile_warning@2x.png</file>
+ <file>images/mac/seafile_warning_white.png</file>
+ <file>images/mac/seafile_warning_white@2x.png</file>
+ <file>images/resync.png</file>
+ <file>images/resync@2x.png</file>
+ <file>images/minus-gray.png</file>
+ <file>images/minus-gray@2x.png</file>
+ <file>images/info.png</file>
+ <file>images/info-gray.png</file>
+ <file>images/info-gray@2x.png</file>
+ <file>images/play-gray.png</file>
+ <file>images/play-gray@2x.png</file>
+ <file>images/pause-gray.png</file>
+ <file>images/pause-gray@2x.png</file>
+ <file>images/cloud-gray.png</file>
+ <file>images/cloud-gray@2x.png</file>
+ <file>images/leave-share.png</file>
+ <file>images/leave-share@2x.png</file>
+ <file>images/sync_now-gray.png</file>
+ <file>images/sync_now-gray@2x.png</file>
+ <file>images/remove-gray.png</file>
+ <file>images/remove-gray@2x.png</file>
+ <file>images/remove-red.png</file>
+ <file>images/share.png</file>
+ <file>images/share@2x.png</file>
+ <file>images/clock.png</file>
+ <file>images/clock@2x.png</file>
+ <file>images/main-panel/folder.png</file>
+ <file>images/main-panel/folder@2x.png</file>
+ <file>images/main-panel/search-background.png</file>
+ <file>images/main-panel/search-background@2x.png</file>
+ <file>images/main-panel/library-normal.png</file>
+ <file>images/main-panel/library-normal@2x.png</file>
+ <file>images/main-panel/library-encrypted.png</file>
+ <file>images/main-panel/library-encrypted@2x.png</file>
+ <file>images/main-panel/library-readonly.png</file>
+ <file>images/main-panel/library-readonly@2x.png</file>
+ <file>images/main-panel/network-error.png</file>
+ <file>images/main-panel/network-error@2x.png</file>
+ <file>images/main-panel/upload.png</file>
+ <file>images/main-panel/upload@2x.png</file>
+ <file>images/main-panel/download.png</file>
+ <file>images/main-panel/download@2x.png</file>
+ <file>images/sync/done.png</file>
+ <file>images/sync/done@2x.png</file>
+ <file>images/sync/cloud-sync.png</file>
+ <file>images/sync/cloud-sync@2x.png</file>
+ <file>images/sync/cloud-synced.png</file>
+ <file>images/sync/cloud-synced@2x.png</file>
+ <file>images/sync/cloud-unsynced.png</file>
+ <file>images/sync/cloud-unsynced@2x.png</file>
+ <file>images/sync/exclamation.png</file>
+ <file>images/sync/minus-sign.png</file>
+ <file>images/sync/pause.png</file>
+ <file>images/sync/pause@2x.png</file>
+ <file>images/sync/question.png</file>
+ <file>images/sync/status-done.png</file>
+ <file>images/sync/status-done@2x.png</file>
+ <file>images/sync/status-syncing.png</file>
+ <file>images/sync/status-syncing@2x.png</file>
+ <file>images/sync/waiting.png</file>
+ <file>images/sync/waiting@2x.png</file>
+ <file>images/download-48.png</file>
+ <file>images/tabs/star-normal.png</file>
+ <file>images/tabs/star-normal@2x.png</file>
+ <file>images/tabs/history-normal.png</file>
+ <file>images/tabs/history-normal@2x.png</file>
+ <file>images/tabs/search-normal.png</file>
+ <file>images/tabs/search-normal@2x.png</file>
+ <file>images/tabs/library-normal.png</file>
+ <file>images/tabs/library-normal@2x.png</file>
+ <file>images/tabs/highlighted/star-orange.png</file>
+ <file>images/tabs/highlighted/star-orange@2x.png</file>
+ <file>images/tabs/highlighted/library-orange.png</file>
+ <file>images/tabs/highlighted/library-orange@2x.png</file>
+ <file>images/tabs/highlighted/search-orange.png</file>
+ <file>images/tabs/highlighted/search-orange@2x.png</file>
+ <file>images/tabs/highlighted/history-orange.png</file>
+ <file>images/tabs/highlighted/history-orange@2x.png</file>
+ <file>images/files/file_audio.png</file>
+ <file>images/library-256.png</file>
+ <file>images/files/file_audio@2x.png</file>
+ <file>images/files/file_folder.png</file>
+ <file>images/files/file_folder@2x.png</file>
+ <file>images/files/file_folder_readonly.png</file>
+ <file>images/files/file_folder_readonly@2x.png</file>
+ <file>images/files/file_image.png</file>
+ <file>images/files/file_image@2x.png</file>
+ <file>images/files/file_ms_excel.png</file>
+ <file>images/files/file_ms_excel@2x.png</file>
+ <file>images/files/file_ms_ppt.png</file>
+ <file>images/files/file_ms_ppt@2x.png</file>
+ <file>images/files/file_ms_word.png</file>
+ <file>images/files/file_ms_word@2x.png</file>
+ <file>images/files/file_pdf.png</file>
+ <file>images/files/file_pdf@2x.png</file>
+ <file>images/files/file_text.png</file>
+ <file>images/files/file_text@2x.png</file>
+ <file>images/files/file_unknown.png</file>
+ <file>images/files/file_unknown@2x.png</file>
+ <file>images/files/file_video.png</file>
+ <file>images/files/file_video@2x.png</file>
+ <file>images/files/file_zip.png</file>
+ <file>images/files/file_zip@2x.png</file>
+ <file>images/files_v2/file_audio.png</file>
+ <file>images/files_v2/file_audio@2x.png</file>
+ <file>images/files_v2/file_folder_readonly.png</file>
+ <file>images/files_v2/file_folder_readonly@2x.png</file>
+ <file>images/files_v2/file_folder.png</file>
+ <file>images/files_v2/file_folder@2x.png</file>
+ <file>images/files_v2/file_image.png</file>
+ <file>images/files_v2/file_image@2x.png</file>
+ <file>images/files_v2/file_ms_excel.png</file>
+ <file>images/files_v2/file_ms_excel@2x.png</file>
+ <file>images/files_v2/file_ms_ppt.png</file>
+ <file>images/files_v2/file_ms_ppt@2x.png</file>
+ <file>images/files_v2/file_ms_word.png</file>
+ <file>images/files_v2/file_ms_word@2x.png</file>
+ <file>images/files_v2/file_pdf.png</file>
+ <file>images/files_v2/file_pdf@2x.png</file>
+ <file>images/files_v2/file_text.png</file>
+ <file>images/files_v2/file_text@2x.png</file>
+ <file>images/files_v2/file_video.png</file>
+ <file>images/files_v2/file_video@2x.png</file>
+ <file>images/files_v2/file_zip.png</file>
+ <file>images/files_v2/file_zip@2x.png</file>
+ <file>images/files_v2/file_unknown.png</file>
+ <file>images/files_v2/file_unknown@2x.png</file>
+ <file>images/account-settings.png</file>
+ <file>images/account-settings@2x.png</file>
+ <file>images/add-account.png</file>
+ <file>images/add-account@2x.png</file>
+ <file>images/delete-account.png</file>
+ <file>images/delete-account@2x.png</file>
+ <file>images/account-checked.png</file>
+ <file>images/account-checked@2x.png</file>
+ <file>images/account-else.png</file>
+ <file>images/account-else@2x.png</file>
+ <file>images/logout.png</file>
+ <file>images/logout@2x.png</file>
+ <file>images/cancel.png</file>
+ <file>images/cancel@2x.png</file>
+ <file>images/filebrowser/backward.png</file>
+ <file>images/filebrowser/backward@2x.png</file>
+ <file>images/filebrowser/forward.png</file>
+ <file>images/filebrowser/forward@2x.png</file>
+ <file>images/filebrowser/home.png</file>
+ <file>images/filebrowser/home@2x.png</file>
+ <file>images/filebrowser/path-separator.png</file>
+ <file>images/filebrowser/path-separator@2x.png</file>
+ <file>images/filebrowser/settings.png</file>
+ <file>images/filebrowser/settings@2x.png</file>
+ <file>images/filebrowser/up-arrow.png</file>
+ <file>images/filebrowser/down-arrow.png</file>
+ <file>images/filebrowser/locked.png</file>
+ <file>images/filebrowser/locked@2x.png</file>
+ <file>images/filebrowser/locked-by-me.png</file>
+ <file>images/filebrowser/locked-by-me@2x.png</file>
+ <file>images/filebrowser/refresh-gray.png</file>
+ <file>images/filebrowser/refresh-gray@2x.png</file>
+ <file>images/filebrowser/add.png</file>
+ <file>images/filebrowser/add@2x.png</file>
+ <file>images/toolbar/add.png</file>
+ <file>images/toolbar/add@2x.png</file>
+ <file>images/toolbar/add-gray.png</file>
+ <file>images/toolbar/add-gray@2x.png</file>
+ <file>images/toolbar/download.png</file>
+ <file>images/toolbar/download@2x.png</file>
+ <file>images/toolbar/download-gray.png</file>
+ <file>images/toolbar/download-gray@2x.png</file>
+ <file>images/toolbar/file.png</file>
+ <file>images/toolbar/file@2x.png</file>
+ <file>images/toolbar/file-gray.png</file>
+ <file>images/toolbar/file-gray@2x.png</file>
+ <file>images/toolbar/refresh-gray.png</file>
+ <file>images/toolbar/refresh-gray@2x.png</file>
+ <file>images/toolbar/refresh.png</file>
+ <file>images/toolbar/refresh@2x.png</file>
+ <file>images/toolbar/refresh-new.png</file>
+ <file>images/toolbar/refresh-new@2x.png</file>
+ <file>images/toolbar/refresh-orange.png</file>
+ <file>images/toolbar/refresh-orange@2x.png</file>
+ <file>qt.css</file>
+ <file>qt-win.css</file>
+ <file>qt-mac.css</file>
+ <file>i18n/seafile_ca.qm</file>
+ <file>i18n/seafile_de_DE.qm</file>
+ <file>i18n/seafile_en.qm</file>
+ <file>i18n/seafile_es.qm</file>
+ <file>i18n/seafile_es_AR.qm</file>
+ <file>i18n/seafile_es_MX.qm</file>
+ <file>i18n/seafile_fr_FR.qm</file>
+ <file>i18n/seafile_he_IL.qm</file>
+ <file>i18n/seafile_hu_HU.qm</file>
+ <file>i18n/seafile_is.qm</file>
+ <file>i18n/seafile_it.qm</file>
+ <file>i18n/seafile_ko_KR.qm</file>
+ <file>i18n/seafile_nl_BE.qm</file>
+ <file>i18n/seafile_pl_PL.qm</file>
+ <file>i18n/seafile_pt_BR.qm</file>
+ <file>i18n/seafile_pt_PT.qm</file>
+ <file>i18n/seafile_ru.qm</file>
+ <file>i18n/seafile_sk_SK.qm</file>
+ <file>i18n/seafile_uk.qm</file>
+ <file>i18n/seafile_zh_CN.qm</file>
+ <file>i18n/seafile_zh_TW.qm</file>
+ <file>i18n/seafile_tr.qm</file>
+ <file>i18n/seafile_nl_NL.qm</file>
+ <file>i18n/seafile_lv.qm</file>
+ <file>i18n/seafile_ja.qm</file>
+ <file>i18n/seafile_sv.qm</file>
+ <file>i18n/seafile_cs_CZ.qm</file>
+ <file>i18n/seafile_el_GR.qm</file>
+ <file>i18n/seafile_nb_NO.qm</file>
+</qresource>
+</RCC>
--- /dev/null
+## Setup WinSparkle environment
+
+[WinSparkle](https://github.com/vslavik/winsparkle) 是 Mac 上的 Sparkle 框架在 windows 上的实现,用于软件自动更新.
+
+* 下载 winsparkle 发布包 https://github.com/vslavik/winsparkle/releases/download/v0.5.3/WinSparkle-0.5.3.zip, 并解压
+* 把 include 下的文件拷贝到 /usr/local/lib
+* 把 Release/winsparkle.dll 拷贝到 /mingw32/bin
+* 把 winsparkle.lib 拷贝到 seafile-client 目录下
+
+在编译时需要加上 `BUILD_SPARKLE_SUPPORT` flag:
+```sh
+cmake -DBUILD_SPARKLE_SUPPORT=ON .
+```
+
+
+## 更新 appcast.xml
+
+winsparkle 根据下载下来的 appcast.xml 中的数据:
+
+- 判断当前是否有更新版本
+- 新版本的下载地址
+- 新版本的 release notes (展示给用户看)
+
+发布新的版本时,需要更新appcast中的哪些字段:
+
+- pubDate 字段
+- enclosure 中新版本的下载地址 url 字段
+- enclosure 中新版本的版本号 sparkle:version 字段
+
+### 本地开发时如何搭建一个简单的 server 来让 seafile-client 去获取 appcast.xml
+
+- 将 appcast.example.xml 修改一下
+- 然后本地启动一个 nginx 服务器
+- 设置 `SEAFILE_CLIENT_APPCAST_URI` 环境变量, 然后启动 seafile-applet.
+
+```sh
+export SEAFILE_CLIENT_APPCAST_URI=http://localhost:8888/appcast.xml
+./seafile-applet.exe
+```
--- /dev/null
+#include <QTimer>
+
+#include "account-info-service.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "seafile-applet.h"
+
+namespace
+{
+// const int kRefreshInterval = 3 * 60 * 1000; // 3 min
+}
+
+SINGLETON_IMPL(AccountInfoService)
+
+AccountInfoService::AccountInfoService(QObject* parent)
+ : QObject(parent)
+{
+ refresh_timer_ = new QTimer(this);
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+ // refresh();
+}
+
+void AccountInfoService::start()
+{
+ // refresh_timer_->start(kRefreshInterval);
+}
+
+void AccountInfoService::stop()
+{
+ refresh_timer_->stop();
+}
+
+void AccountInfoService::refresh()
+{
+ const Account account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ return;
+ }
+
+ FetchAccountInfoRequest* fetch_account_info_request = new FetchAccountInfoRequest(account);
+ connect(fetch_account_info_request, SIGNAL(success(const AccountInfo&)), this,
+ SLOT(onFetchAccountInfoSuccess(const AccountInfo&)));
+ connect(fetch_account_info_request, SIGNAL(failed(const ApiError&)), this,
+ SLOT(onFetchAccountInfoFailed()));
+ fetch_account_info_request->send();
+}
+
+
+void AccountInfoService::onFetchAccountInfoSuccess(const AccountInfo& info)
+{
+ FetchAccountInfoRequest *req = (FetchAccountInfoRequest *)QObject::sender();
+ seafApplet->accountManager()->updateAccountInfo(req->account(), info);
+ req->deleteLater();
+ req = NULL;
+}
+
+void AccountInfoService::onFetchAccountInfoFailed()
+{
+ FetchAccountInfoRequest *req = (FetchAccountInfoRequest *)QObject::sender();
+ req->deleteLater();
+ req = NULL;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_ACCOUNT_INFO_SERVICE_H
+#define SEAFILE_CLIENT_ACCOUNT_INFO_SERVICE_H
+
+#include <QObject>
+#include <QList>
+#include <QUrl>
+#include <QHash>
+
+#include "utils/singleton.h"
+
+class QTimer;
+
+class FetchAccountInfoRequest;
+class ApiError;
+class AccountInfo;
+
+
+class AccountInfoService : public QObject
+{
+ Q_OBJECT
+ SINGLETON_DEFINE(AccountInfoService)
+
+public:
+ void start();
+ void stop();
+
+public slots:
+ void refresh();
+
+private slots:
+ void onFetchAccountInfoSuccess(const AccountInfo& info);
+ void onFetchAccountInfoFailed();
+
+private:
+ Q_DISABLE_COPY(AccountInfoService)
+ AccountInfoService(QObject *parent=0);
+
+ QTimer *refresh_timer_;
+};
+
+
+#endif // SEAFILE_CLIENT_ACCOUNT_INFO_SERVICE_H
--- /dev/null
+#include <sqlite3.h>
+#include <glib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <algorithm>
+
+#include <QDateTime>
+#include <QMutexLocker>
+
+#include "account-mgr.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "utils/utils.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "account-info-service.h"
+#include "ui/login-dialog.h"
+#include "shib/shib-login-dialog.h"
+#include "settings-mgr.h"
+
+namespace {
+const char *kRepoServerUrlProperty = "server-url";
+const char *kVersionKeyName = "version";
+const char *kFeaturesKeyName = "features";
+const char *kEncryptedLibraryVersionName = "encrypted_library_version";
+const char *kCustomBrandKeyName = "custom-brand";
+const char *kCustomLogoKeyName = "custom-logo";
+const char *kTotalStorage = "storage.total";
+const char *kUsedStorage = "storage.used";
+const char *kNickname = "name";
+
+struct ColumnCheckData {
+ QString name;
+ bool exists;
+};
+
+bool getColumnInfoCallback(sqlite3_stmt *stmt, void *data)
+{
+ ColumnCheckData *cdata = (ColumnCheckData *)data;
+ const char *column_name = (const char *)sqlite3_column_text (stmt, 1);
+
+ if (cdata->name == QString(column_name)) {
+ cdata->exists = true;
+ return false;
+ }
+
+ return true;
+}
+
+void addNewColumnToAccountsTable(struct sqlite3* db, const QString& name, const QString& type)
+{
+ QString sql = "PRAGMA table_info(Accounts);";
+ ColumnCheckData cdata;
+ cdata.name = name;
+ cdata.exists = false;
+ sqlite_foreach_selected_row (db, toCStr(sql), getColumnInfoCallback, &cdata);
+ if (!cdata.exists) {
+ sql = QString("ALTER TABLE Accounts ADD COLUMN %1 %2").arg(name).arg(type);
+ if (sqlite_query_exec (db, toCStr(sql)) < 0) {
+ qCritical("unable to create column %s\n", toCStr(name));
+ }
+ }
+}
+
+bool compareAccount(const Account& a, const Account& b)
+{
+ if (!a.isValid()) {
+ return false;
+ } else if (!b.isValid()) {
+ return true;
+ } else if (a.lastVisited < b.lastVisited) {
+ return false;
+ } else if (a.lastVisited > b.lastVisited) {
+ return true;
+ }
+
+ return true;
+}
+
+struct UserData {
+ std::vector<Account> *accounts;
+ struct sqlite3 *db;
+};
+
+inline void setServerInfoKeyValue(struct sqlite3 *db, const Account &account, const QString& key, const QString &value)
+{
+ char *zql = sqlite3_mprintf(
+ "REPLACE INTO ServerInfo(url, username, key, value) VALUES (%Q, %Q, %Q, %Q)",
+ account.serverUrl.toEncoded().data(), account.username.toUtf8().data(),
+ key.toUtf8().data(), value.toUtf8().data());
+ sqlite_query_exec(db, zql);
+ sqlite3_free(zql);
+}
+
+QStringList collectSyncedReposForAccount(const Account& account)
+{
+ std::vector<LocalRepo> repos;
+ SeafileRpcClient *rpc = seafApplet->rpcClient();
+ rpc->listLocalRepos(&repos);
+ QStringList repo_ids;
+ for (size_t i = 0; i < repos.size(); i++) {
+ LocalRepo repo = repos[i];
+ QString repo_server_url;
+ if (rpc->getRepoProperty(repo.id, kRepoServerUrlProperty, &repo_server_url) < 0) {
+ continue;
+ }
+ if (QUrl(repo_server_url).host() != account.serverUrl.host()) {
+ continue;
+ }
+ QString token;
+ if (rpc->getRepoProperty(repo.id, "token", &token) < 0 || token.isEmpty()) {
+ repo_ids.append(repo.id);
+ }
+ }
+
+ return repo_ids;
+}
+
+}
+
+AccountManager::AccountManager()
+{
+ db = NULL;
+}
+
+AccountManager::~AccountManager()
+{
+ if (db)
+ sqlite3_close(db);
+}
+
+int AccountManager::start()
+{
+ const char *errmsg;
+ const char *sql;
+
+ QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
+ if (sqlite3_open (toCStr(db_path), &db)) {
+ errmsg = sqlite3_errmsg (db);
+ qCritical("failed to open account database %s: %s",
+ toCStr(db_path), errmsg ? errmsg : "no error given");
+
+ seafApplet->errorAndExit(tr("failed to open account database"));
+ return -1;
+ }
+
+ // enabling foreign keys, it must be done manually from each connection
+ // and this feature is only supported from sqlite 3.6.19
+ sql = "PRAGMA foreign_keys=ON;";
+ if (sqlite_query_exec (db, sql) < 0) {
+ qCritical("sqlite version is too low to support foreign key feature\n");
+ sqlite3_close(db);
+ db = NULL;
+ return -1;
+ }
+
+ sql = "CREATE TABLE IF NOT EXISTS Accounts (url VARCHAR(24), "
+ "username VARCHAR(15), token VARCHAR(40), lastVisited INTEGER, "
+ "PRIMARY KEY(url, username))";
+ if (sqlite_query_exec (db, sql) < 0) {
+ qCritical("failed to create accounts table\n");
+ sqlite3_close(db);
+ db = NULL;
+ return -1;
+ }
+
+ addNewColumnToAccountsTable(db, "isShibboleth", "INTEGER");
+ addNewColumnToAccountsTable(db, "AutomaticLogin", "INTEGER default 1");
+ addNewColumnToAccountsTable(db, "s2fa_token", "TEXT");
+
+ // ServerInfo table is used to store any (key, value) information for an
+ // account.
+ sql = "CREATE TABLE IF NOT EXISTS ServerInfo ("
+ "key TEXT NOT NULL, value TEXT, "
+ "url VARCHAR(24), username VARCHAR(15), "
+ "PRIMARY KEY(url, username, key), "
+ "FOREIGN KEY(url, username) REFERENCES Accounts(url, username) "
+ "ON DELETE CASCADE ON UPDATE CASCADE )";
+ if (sqlite_query_exec (db, sql) < 0) {
+ qCritical("failed to create server_info table\n");
+ sqlite3_close(db);
+ db = NULL;
+ return -1;
+ }
+
+ loadAccounts();
+
+ connect(this, SIGNAL(accountsChanged()), this, SLOT(onAccountsChanged()));
+ connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(onAboutToQuit()));
+ connect(this, SIGNAL(accountRequireRelogin(const Account&)),
+ this, SLOT(reloginAccount(const Account &)));
+ return 0;
+}
+
+void AccountManager::onAboutToQuit()
+{
+ logoutDeviceNonautoLogin();
+}
+
+bool AccountManager::loadAccountsCB(sqlite3_stmt *stmt, void *data)
+{
+ UserData *userdata = static_cast<UserData*>(data);
+ const char *url = (const char *)sqlite3_column_text (stmt, 0);
+ const char *username = (const char *)sqlite3_column_text (stmt, 1);
+ const char *token = (const char *)sqlite3_column_text (stmt, 2);
+ qint64 atime = (qint64)sqlite3_column_int64 (stmt, 3);
+ int isShibboleth = sqlite3_column_int (stmt, 4);
+ int isAutomaticLogin = sqlite3_column_int (stmt, 5);
+ const char *s2fa_token = (const char *)sqlite3_column_text (stmt,6);
+
+ if (!token) {
+ token = "";
+ }
+
+ if (!s2fa_token) {
+ s2fa_token = "";
+ }
+
+ Account account = Account(QUrl(QString(url)), QString(username),
+ QString(token), atime, isShibboleth != 0,
+ isAutomaticLogin != 0, QString(s2fa_token));
+ char* zql = sqlite3_mprintf("SELECT key, value FROM ServerInfo WHERE url = %Q AND username = %Q", url, username);
+ sqlite_foreach_selected_row (userdata->db, zql, loadServerInfoCB, &account);
+ sqlite3_free(zql);
+
+ userdata->accounts->push_back(account);
+ return true;
+}
+
+bool AccountManager::loadServerInfoCB(sqlite3_stmt *stmt, void *data)
+{
+ Account *account = static_cast<Account*>(data);
+ const char *key = (const char *)sqlite3_column_text (stmt, 0);
+ const char *value = (const char *)sqlite3_column_text (stmt, 1);
+ QString key_string = key;
+ QString value_string = value;
+ if (key_string == kVersionKeyName) {
+ account->serverInfo.parseVersionFromString(value_string);
+ } else if (key_string == kEncryptedLibraryVersionName) {
+ account->serverInfo.parseEncryptedLibraryVersionFromString(value_string);
+ } else if (key_string == kFeaturesKeyName) {
+ account->serverInfo.parseFeatureFromStrings(value_string.split(","));
+ } else if (key_string == kCustomBrandKeyName) {
+ account->serverInfo.customBrand = value_string;
+ } else if (key_string == kCustomLogoKeyName) {
+ account->serverInfo.customLogo = value_string;
+ } else if (key_string == kTotalStorage) {
+ account->accountInfo.totalStorage = value_string.toLongLong();
+ } else if (key_string == kUsedStorage) {
+ account->accountInfo.usedStorage = value_string.toLongLong();
+ } else if (key_string == kNickname) {
+ account->accountInfo.name = value_string;
+ }
+ return true;
+}
+
+const std::vector<Account>& AccountManager::loadAccounts()
+{
+ const char *sql = "SELECT url, username, token, lastVisited, isShibboleth, AutomaticLogin, s2fa_token "
+ "FROM Accounts ORDER BY lastVisited DESC";
+ accounts_.clear();
+ UserData userdata;
+ userdata.accounts = &accounts_;
+ userdata.db = db;
+ sqlite_foreach_selected_row (db, sql, loadAccountsCB, &userdata);
+
+ std::stable_sort(accounts_.begin(), accounts_.end(), compareAccount);
+ return accounts_;
+}
+
+void AccountManager::setCurrentAccount(const Account& account)
+{
+ Q_ASSERT(account.isValid());
+
+ emit beforeAccountSwitched();
+
+ Account new_account = account;
+ bool account_exist = false;
+ {
+ QMutexLocker lock(&accounts_mutex_);
+ size_t i;
+ for (i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i] == account) {
+ accounts_.erase(accounts_.begin() + i);
+ account_exist = true;
+ break;
+ }
+ }
+ accounts_.insert(accounts_.begin(), new_account);
+ }
+ AccountInfoService::instance()->refresh();
+ updateAccountServerInfo(new_account);
+
+ qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
+
+ char *zql;
+ if (account_exist) {
+ zql = sqlite3_mprintf(
+ "UPDATE Accounts SET token = %Q, lastVisited = %Q, isShibboleth = %Q, AutomaticLogin = %Q, s2fa_token = %Q"
+ "WHERE url = %Q AND username = %Q",
+ // token
+ new_account.token.toUtf8().data(),
+ // lastVisited
+ QString::number(timestamp).toUtf8().data(),
+ // isShibboleth
+ QString::number(new_account.isShibboleth).toUtf8().data(),
+ // isAutomaticLogin
+ QString::number(new_account.isAutomaticLogin).toUtf8().data(),
+ //s2fa_token
+ new_account.s2fa_token.toUtf8().data(),
+ // url
+ new_account.serverUrl.toEncoded().data(),
+ // username
+ new_account.username.toUtf8().data());
+ } else {
+ zql = sqlite3_mprintf(
+ "INSERT INTO Accounts(url, username, token, lastVisited, isShibboleth, AutomaticLogin, s2fa_token) "
+ "VALUES (%Q, %Q, %Q, %Q, %Q, %Q, %Q) ",
+ // url
+ new_account.serverUrl.toEncoded().data(),
+ // username
+ new_account.username.toUtf8().data(),
+ // token
+ new_account.token.toUtf8().data(),
+ // lastVisited
+ QString::number(timestamp).toUtf8().data(),
+ // isShibboleth
+ QString::number(new_account.isShibboleth).toUtf8().data(),
+ // isAutomaticLogin
+ QString::number(new_account.isAutomaticLogin).toUtf8().data(),
+ //s2fa_token
+ new_account.s2fa_token.toUtf8().data());
+ }
+ sqlite_query_exec(db, zql);
+ sqlite3_free(zql);
+
+ emit accountsChanged();
+}
+
+int AccountManager::removeAccount(const Account& account)
+{
+ char *zql = sqlite3_mprintf(
+ "DELETE FROM Accounts WHERE url = %Q AND username = %Q",
+ // url
+ account.serverUrl.toEncoded().data(),
+ // username
+ account.username.toUtf8().data());
+ sqlite_query_exec(db, zql);
+ sqlite3_free(zql);
+
+ bool need_switch_account = currentAccount() == account;
+
+ {
+ QMutexLocker lock(&accounts_mutex_);
+ accounts_.erase(
+ std::remove(accounts_.begin(), accounts_.end(), account),
+ accounts_.end());
+ }
+
+ if (need_switch_account) {
+ if (!accounts_.empty()) {
+ validateAndUseAccount(accounts_[0]);
+ } else {
+ LoginDialog login_dialog;
+ login_dialog.exec();
+ }
+ }
+
+ emit accountsChanged();
+
+ return 0;
+}
+
+void AccountManager::logoutDevice(const Account& account)
+{
+ clearSyncToken(account);
+ clearAccountToken(account);
+}
+
+void AccountManager::logoutDeviceNonautoLogin()
+{
+ QMutexLocker lock(&accounts_mutex_);
+ for (const Account& account : accounts_) {
+ if (account.isAutomaticLogin) {
+ continue;
+ }
+ clearSyncToken(account);
+ clearAccountToken(account);
+ }
+}
+
+void AccountManager::updateAccountLastVisited(const Account& account)
+{
+ char *zql = sqlite3_mprintf(
+ "UPDATE Accounts SET lastVisited = %Q "
+ "WHERE url = %Q AND username = %Q",
+ // lastVisted
+ QString::number(QDateTime::currentMSecsSinceEpoch()).toUtf8().data(),
+ // url
+ account.serverUrl.toEncoded().data(),
+ // username
+ account.username.toUtf8().data());
+ sqlite_query_exec(db, zql);
+ sqlite3_free(zql);
+}
+
+bool AccountManager::accountExists(const QUrl& url, const QString& username) const
+{
+ for (size_t i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i].serverUrl == url && accounts_[i].username == username) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void AccountManager::validateAndUseAccount(const Account& account)
+{
+ if (!account.isAutomaticLogin) {
+ clearAccountToken(account);
+ reloginAccount(account);
+ } else if (!account.isValid()) {
+ reloginAccount(account);
+ } else {
+ setCurrentAccount(account);
+ }
+}
+
+int AccountManager::replaceAccount(const Account& old_account, const Account& new_account)
+{
+ {
+ QMutexLocker lock(&accounts_mutex_);
+ for (size_t i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i] == old_account) {
+ // TODO copy new_account and old_account before this operation
+ // we might have invalid old_account or new_account after it
+ accounts_[i] = new_account;
+ updateAccountServerInfo(new_account);
+ break;
+ }
+ }
+ }
+
+ qint64 timestamp = QDateTime::currentMSecsSinceEpoch();
+
+ char *zql = sqlite3_mprintf(
+ "UPDATE Accounts "
+ "SET url = %Q, "
+ " username = %Q, "
+ " token = %Q, "
+ " lastVisited = %Q, "
+ " isShibboleth = %Q, "
+ " AutomaticLogin = %Q "
+ "WHERE url = %Q "
+ " AND username = %Q",
+ // new_url
+ new_account.serverUrl.toEncoded().data(),
+ // username
+ new_account.username.toUtf8().data(),
+ // token
+ new_account.token.toUtf8().data(),
+ // lastvisited
+ QString::number(timestamp).toUtf8().data(),
+ // isShibboleth
+ QString::number(new_account.isShibboleth).toUtf8().data(),
+ // isAutomaticLogin
+ QString::number(new_account.isAutomaticLogin).toUtf8().data(),
+ // old_url
+ old_account.serverUrl.toEncoded().data(),
+ // username
+ new_account.username.toUtf8().data()
+ );
+
+ sqlite_query_exec(db, zql);
+ sqlite3_free(zql);
+
+ emit accountsChanged();
+
+ return 0;
+}
+
+Account AccountManager::getAccountByHostAndUsername(const QString& host,
+ const QString& username) const
+{
+ for (size_t i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i].serverUrl.host() == host
+ && accounts_[i].username == username) {
+ return accounts_[i];
+ }
+ }
+
+ return Account();
+}
+
+Account AccountManager::getAccountBySignature(const QString& account_sig) const
+{
+ for (size_t i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i].getSignature() == account_sig) {
+ return accounts_[i];
+ }
+ }
+
+ return Account();
+}
+
+void AccountManager::updateServerInfoForAllAccounts()
+{
+ for (size_t i = 0; i < accounts_.size(); i++)
+ updateAccountServerInfo(accounts_[i]);
+}
+
+void AccountManager::updateAccountServerInfo(const Account& account)
+{
+ ServerInfoRequest *request = new ServerInfoRequest(account);
+ connect(request, SIGNAL(success(const Account&, const ServerInfo &)),
+ this, SLOT(serverInfoSuccess(const Account&, const ServerInfo &)));
+ connect(request, SIGNAL(failed(const ApiError&)),
+ this, SLOT(serverInfoFailed(const ApiError&)));
+ request->send();
+}
+
+void AccountManager::updateAccountInfo(const Account& account,
+ const AccountInfo& info)
+{
+ setServerInfoKeyValue(db, account, kTotalStorage,
+ QString::number(info.totalStorage));
+ setServerInfoKeyValue(db, account, kUsedStorage,
+ QString::number(info.usedStorage));
+ setServerInfoKeyValue(db, account, kNickname,
+ info.name);
+
+ for (size_t i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i] == account) {
+ accounts_[i].accountInfo = info;
+ emit accountInfoUpdated(accounts_[i]);
+ break;
+ }
+ }
+}
+
+
+void AccountManager::serverInfoSuccess(const Account &_account, const ServerInfo &info)
+{
+ ServerInfoRequest *req = (ServerInfoRequest *)(sender());
+ req->deleteLater();
+
+ Account account = _account;
+ account.serverInfo = info;
+
+ setServerInfoKeyValue(db, account, kVersionKeyName, info.getVersionString());
+ setServerInfoKeyValue(db, account, kEncryptedLibraryVersionName, QString::number(info.getEncryptedLibraryVersion()));
+ setServerInfoKeyValue(db, account, kFeaturesKeyName, info.getFeatureStrings().join(","));
+ setServerInfoKeyValue(db, account, kCustomLogoKeyName, info.customLogo);
+ setServerInfoKeyValue(db, account, kCustomBrandKeyName, info.customBrand);
+
+ bool changed = _account.serverInfo != info;
+ if (!changed)
+ return;
+
+ QUrl url(account.serverUrl);
+ url.setPath("/");
+ seafApplet->rpcClient()->setServerProperty(
+ url.toString(), "is_pro", account.isPro() ? "true" : "false");
+
+ for (size_t i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i] == account) {
+ if (i == 0)
+ emit beforeAccountSwitched();
+ accounts_[i].serverInfo = info;
+ if (i == 0)
+ emit accountsChanged();
+ break;
+ }
+ }
+}
+
+void AccountManager::serverInfoFailed(const ApiError &error)
+{
+ ServerInfoRequest *req = (ServerInfoRequest *)(sender());
+ req->deleteLater();
+
+ qWarning("update server info failed %s\n", error.toString().toUtf8().data());
+}
+
+void AccountManager::clearAccountToken(const Account& account)
+{
+ for (size_t i = 0; i < accounts_.size(); i++) {
+ if (accounts_[i] == account) {
+ accounts_[i].token = "";
+ break;
+ }
+ }
+
+ char *zql = sqlite3_mprintf(
+ "UPDATE Accounts "
+ "SET token = NULL "
+ "WHERE url = %Q "
+ " AND username = %Q",
+ // url
+ account.serverUrl.toEncoded().data(),
+ // username
+ account.username.toUtf8().data()
+ );
+ sqlite_query_exec(db, zql);
+ sqlite3_free(zql);
+
+ emit accountsChanged();
+}
+
+void AccountManager::clearSyncToken(const Account& account)
+{
+ QString error;
+ QUrl url = account.serverUrl;
+ url.setPath("/");
+ if (seafApplet->rpcClient()->removeSyncTokensByAccount(url,
+ account.username,
+ &error) < 0) {
+ seafApplet->warningBox(
+ tr("Failed to remove local repos sync token: %1").arg(error));
+ }
+}
+
+void AccountManager::removeNonautoLoginSyncTokens()
+{
+ QMutexLocker lock(&accounts_mutex_);
+ for (const Account& account : accounts_) {
+ if (account.isAutomaticLogin) {
+ continue;
+ }
+
+ clearSyncToken(account);
+ }
+ return;
+}
+
+Account AccountManager::getAccountByRepo(const QString& repo_id, SeafileRpcClient *rpc)
+{
+ std::vector<Account> accounts;
+ {
+ QMutexLocker lock(&accounts_mutex_);
+ accounts = accounts_;
+ }
+
+ QMutexLocker cache_lock(&accounts_cache_mutex_);
+
+ if (!accounts_cache_.contains(repo_id)) {
+ QString server_url;
+ if (rpc->getRepoProperty(repo_id, kRepoServerUrlProperty, &server_url) < 0) {
+ return Account();
+ }
+ QString server_host = QUrl(server_url).host();
+ for (size_t i = 0; i < accounts.size(); i++) {
+ const Account& account = accounts[i];
+ if (account.serverUrl.host() == server_host) {
+ accounts_cache_[repo_id] = account;
+ break;
+ }
+ }
+ }
+ return accounts_cache_.value(repo_id, Account());
+}
+
+Account AccountManager::getAccountByRepo(const QString& repo_id)
+{
+ return getAccountByRepo(repo_id, seafApplet->rpcClient());
+}
+
+void AccountManager::onAccountsChanged()
+{
+ QMutexLocker cache_lock(&accounts_cache_mutex_);
+ accounts_cache_.clear();
+}
+
+void AccountManager::invalidateCurrentLogin()
+{
+ // make sure we have accounts there
+ if (!hasAccount())
+ return;
+ const Account &account = accounts_.front();
+ // if the token is already invalidated, ignore
+ if (account.token.isEmpty())
+ return;
+
+ emit accountAboutToRelogin(account);
+
+ clearSyncToken(account);
+ clearAccountToken(account);
+ seafApplet->warningBox(tr("Authorization expired, please re-login"));
+
+ emit accountRequireRelogin(account);
+}
+
+void AccountManager::reloginAccount(const Account &account_in)
+{
+ qWarning("Relogin to account %s", account_in.username.toUtf8().data());
+ bool accepted;
+
+ // Make a copy of the account arugment because it may be released after the
+ // login succeeded.
+ //
+ // See: https://github.com/haiwen/seafile-client/blob/v6.1.3/src/account-mgr.cpp#L219
+ // See: https://gist.github.com/lins05/f952356ba8733d5aa19b54a6db19f69a
+ const Account account(account_in);
+
+ do {
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+ if (account.isShibboleth) {
+ ShibLoginDialog shib_dialog(
+ account.serverUrl, seafApplet->settingsManager()->getComputerName());
+ accepted = shib_dialog.exec() == QDialog::Accepted;
+ break;
+ }
+#endif // HAVE_SHIBBOLETH_SUPPORT
+ LoginDialog dialog;
+ dialog.initFromAccount(account);
+ accepted = dialog.exec() == QDialog::Accepted;
+ } while (0);
+
+ if (accepted) {
+ // Accepted means the relogin has succeeded, which means the
+ // current account is the newly relogged in account.
+ getSyncedReposToken(currentAccount());
+ }
+}
+
+void AccountManager::getSyncedReposToken(const Account& account)
+{
+ QStringList repo_ids = collectSyncedReposForAccount(account);
+ if (repo_ids.empty()) {
+ return;
+ }
+
+ // For debugging lots of repos problem.
+ // TODO: Comment this out before committing!!
+ //
+ // int targetNumberForDebug = 300;
+ // while (repo_ids.size() < targetNumberForDebug) {
+ // repo_ids.append(repo_ids);
+ // }
+ // repo_ids = repo_ids.mid(0, 300);
+ // printf ("repo_ids.size() = %d\n", repo_ids.size());
+
+ sendGetRepoTokensRequet(account, repo_ids, 3);
+}
+
+
+void AccountManager::sendGetRepoTokensRequet(const Account& account,
+ const QStringList& repo_ids,
+ int max_retries)
+{
+ GetRepoTokensRequest *req = new GetRepoTokensRequest(
+ account, repo_ids, max_retries);
+
+ connect(req, SIGNAL(success()),
+ this, SLOT(onGetRepoTokensSuccess()));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetRepoTokensFailed(const ApiError&)));
+ req->send();
+}
+
+void AccountManager::onGetRepoTokensSuccess()
+{
+ GetRepoTokensRequest *req = (GetRepoTokensRequest *)(sender());
+ foreach (const QString& repo_id, req->repoTokens().keys()) {
+ seafApplet->rpcClient()->setRepoToken(
+ repo_id, req->repoTokens().value(repo_id));
+ }
+ req->deleteLater();
+}
+
+void AccountManager::onGetRepoTokensFailed(const ApiError& error)
+{
+ GetRepoTokensRequest *req = (GetRepoTokensRequest *)QObject::sender();
+ qWarning("retry get repo tokens request, error = %s", toCStr(error.toString()));
+ seafApplet->warningBox(
+ tr("Failed to get repo sync information from server: %1").arg(error.toString()));
+ if (req->maxRetries() > 0) {
+ sendGetRepoTokensRequet(req->account(), req->repoIds(), req->maxRetries() - 1);
+ }
+ req->deleteLater();
+}
+
+const std::vector<Account>& AccountManager::accounts() const
+{
+ return accounts_;
+}
+
+bool AccountManager::hasAccount() const {
+ return !accounts_.empty();
+}
+
+const Account AccountManager::currentAccount() const {
+ return hasAccount() ? accounts_[0] : Account();
+}
--- /dev/null
+#ifndef _SEAF_ACCOUNT_MGR_H
+#define _SEAF_ACCOUNT_MGR_H
+
+#include <vector>
+
+#include <QObject>
+#include <QHash>
+#include <QMutex>
+
+#include "account.h"
+
+struct sqlite3;
+struct sqlite3_stmt;
+class ApiError;
+class SeafileRpcClient;
+
+
+class AccountManager : public QObject {
+ Q_OBJECT
+
+public:
+ AccountManager();
+ ~AccountManager();
+
+ int start();
+
+ // Load the accounts from local db when client starts.
+ const std::vector<Account>& loadAccounts();
+
+ /**
+ * Account operations
+ */
+
+ // Use the given account. This account would also be persisted to
+ // the accounts db.
+ void setCurrentAccount(const Account& account);
+
+ // Remove the account. Used when user removes an account from the
+ // account menu.
+ int removeAccount(const Account& account);
+
+ // Update the account details. Currently it's only used to update
+ // the server address in AccountSettingsDialog.
+ // TODO: replace this with a more restricted `updateAccountURL` interface.
+ int replaceAccount(const Account& old_account,
+ const Account& new_account);
+
+ // Use the account if it's valid, otherwise require a re-login.
+ void validateAndUseAccount(const Account& account);
+
+ // Called when API returns 401 and we need to re-login current
+ // account.
+ void invalidateCurrentLogin();
+
+ // Update AccountInfo (e.g. nick name, quota etc.) for the given
+ // account.
+ void updateAccountInfo(const Account& account,
+ const AccountInfo& info);
+
+ // Trigger server info refresh for all accounts when client
+ // starts.
+ void updateServerInfoForAllAccounts();
+
+ /**
+ * Logout
+ */
+
+ // Called When the user chooses to log out current account.
+ void logoutDevice(const Account& account);
+ // Before client exits, remove sync tokens for all accounts that
+ // doesn't have auot-login set.
+ void removeNonautoLoginSyncTokens();
+
+ /**
+ * Accessors
+ */
+
+ const std::vector<Account>& accounts() const;
+
+ const Account currentAccount() const;
+
+ bool hasAccount() const;
+
+ bool accountExists(const QUrl& url, const QString& username) const;
+
+ Account getAccountByHostAndUsername(const QString& host,
+ const QString& username) const;
+
+ Account getAccountBySignature(const QString& account_sig) const;
+
+ Account getAccountByRepo(const QString& repo_id);
+
+ Account getAccountByRepo(const QString& repo_id, SeafileRpcClient *rpc);
+
+signals:
+ /**
+ * Account added/removed/switched.
+ */
+ void beforeAccountSwitched();
+ void accountsChanged();
+ void accountAboutToRelogin(const Account& account);
+ void accountRequireRelogin(const Account& account);
+
+ void requireAddAccount();
+ void accountInfoUpdated(const Account& account);
+
+public slots:
+ void reloginAccount(const Account &account);
+
+private slots:
+ void serverInfoSuccess(const Account &account, const ServerInfo &info);
+ void serverInfoFailed(const ApiError&);
+
+ void onAccountsChanged();
+
+ void onAboutToQuit();
+
+ void onGetRepoTokensSuccess();
+ void onGetRepoTokensFailed(const ApiError& error);
+
+private:
+ Q_DISABLE_COPY(AccountManager)
+
+ void updateAccountServerInfo(const Account& account);
+ static bool loadAccountsCB(struct sqlite3_stmt *stmt, void *data);
+ static bool loadServerInfoCB(struct sqlite3_stmt *stmt, void *data);
+
+ void updateAccountLastVisited(const Account& account);
+ void getSyncedReposToken(const Account& account);
+ void sendGetRepoTokensRequet(const Account& account, const QStringList& repo_ids, int max_retries);
+
+ void logoutDeviceNonautoLogin();
+ void clearAccountToken(const Account& account);
+ void clearSyncToken(const Account& account);
+
+ QHash<QString, Account> accounts_cache_;
+
+ struct sqlite3 *db;
+ std::vector<Account> accounts_;
+
+ QMutex accounts_mutex_;
+ QMutex accounts_cache_mutex_;
+};
+
+#endif // _SEAF_ACCOUNT_MGR_H
--- /dev/null
+#include "account.h"
+#include "utils/utils.h"
+#include "api/requests.h"
+
+QUrl Account::getAbsoluteUrl(const QString& relativeUrl) const
+{
+ return ::urlJoin(serverUrl, relativeUrl);
+}
+
+QString Account::getSignature() const
+{
+ if (!isValid()) {
+ return "";
+ }
+
+ return ::md5(serverUrl.host() + username).left(7);
+}
--- /dev/null
+#ifndef ACCOUNT_H
+#define ACCOUNT_H
+
+#include <QUrl>
+#include <QString>
+#include <QMetaType>
+
+#include "api/server-info.h"
+
+class AccountInfo {
+public:
+ QString email;
+ QString name;
+ qint64 totalStorage;
+ qint64 usedStorage;
+};
+
+class Account {
+ friend class AccountManager;
+public:
+ ServerInfo serverInfo;
+ AccountInfo accountInfo;
+ QUrl serverUrl;
+ QString username;
+ QString token;
+ qint64 lastVisited;
+ bool isShibboleth;
+ bool isAutomaticLogin;
+ QString s2fa_token;
+
+ Account() : serverInfo(),
+ lastVisited(0),
+ isShibboleth(false),
+ isAutomaticLogin(true) {}
+ Account(QUrl serverUrl, QString username, QString token,
+ qint64 lastVisited=0, bool isShibboleth = false,
+ bool isAutomaticLogin = true, QString s2fa_token = QString())
+ : serverInfo(),
+ accountInfo(),
+ serverUrl(serverUrl),
+ username(username),
+ token(token),
+ lastVisited(lastVisited),
+ isShibboleth(isShibboleth),
+ isAutomaticLogin(isAutomaticLogin),
+ s2fa_token(s2fa_token) {}
+
+ Account(const Account &rhs)
+ : serverInfo(rhs.serverInfo),
+ accountInfo(rhs.accountInfo),
+ serverUrl(rhs.serverUrl),
+ username(rhs.username),
+ token(rhs.token),
+ lastVisited(rhs.lastVisited),
+ isShibboleth(rhs.isShibboleth),
+ isAutomaticLogin(rhs.isAutomaticLogin),
+ s2fa_token(rhs.s2fa_token)
+ {
+ }
+
+ Account& operator=(const Account&rhs) {
+ serverInfo = rhs.serverInfo;
+ accountInfo = rhs.accountInfo;
+ serverUrl = rhs.serverUrl;
+ username = rhs.username;
+ token = rhs.token;
+ lastVisited = rhs.lastVisited;
+ isShibboleth = rhs.isShibboleth;
+ isAutomaticLogin = rhs.isAutomaticLogin;
+ s2fa_token = rhs.s2fa_token;
+ return *this;
+ }
+
+ bool operator==(const Account& rhs) const {
+ return serverUrl == rhs.serverUrl
+ && username == rhs.username;
+ }
+
+ bool operator!=(const Account& rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool isValid() const {
+ return token.length() > 0;
+ }
+
+ bool hasS2FAToken() const {
+ return s2fa_token.length() > 0;
+ }
+
+ bool isPro() const {
+ return serverInfo.proEdition;
+ }
+
+ bool hasOfficePreview() const {
+ return serverInfo.officePreview;
+ }
+
+ bool hasFileSearch() const {
+ return serverInfo.fileSearch;
+ }
+
+ bool hasDisableSyncWithAnyFolder() const {
+ return serverInfo.disableSyncWithAnyFolder;
+ }
+
+ bool isAtLeastVersion(unsigned majorVersion, unsigned minorVersion, unsigned patchVersion) const {
+ return (serverInfo.majorVersion << 20) +
+ (serverInfo.minorVersion << 10) +
+ (serverInfo.patchVersion) >=
+ (majorVersion << 20) + (minorVersion << 10) + (patchVersion);
+ }
+
+ int getEncryptedLibraryVersion() const {
+ return serverInfo.encryptedLibraryVersion;
+ }
+ // require pro edtions and version at least at ...
+ // excluding OSS Version
+ bool isAtLeastProVersion(unsigned majorVersion, unsigned minorVersion, unsigned patchVersion) const {
+ return isPro() && isAtLeastVersion(majorVersion, minorVersion, patchVersion);
+ }
+
+ // require oss edtions and version at least at ...
+ // excluding Pro Version
+ bool isAtLeastOSSVersion(unsigned majorVersion, unsigned minorVersion, unsigned patchVersion) const {
+ return !isPro() && isAtLeastVersion(majorVersion, minorVersion, patchVersion);
+ }
+
+ qint32 getTotalStorage() const {
+ return accountInfo.totalStorage;
+ }
+
+ qint32 getUsedStorage() const {
+ return accountInfo.usedStorage;
+ }
+
+ QUrl getAbsoluteUrl(const QString& relativeUrl) const;
+ QString getSignature() const;
+};
+
+Q_DECLARE_METATYPE(Account)
+
+#endif // ACCOUNT_H
--- /dev/null
+#include <QUrl>
+#include <QtNetwork>
+#include <QSslError>
+#include <QSslConfiguration>
+#include <QSslCertificate>
+#include <QNetworkConfigurationManager>
+
+#include "seafile-applet.h"
+#include "customization-service.h"
+#include "certs-mgr.h"
+#include "ui/main-window.h"
+#include "ui/ssl-confirm-dialog.h"
+#include "utils/utils.h"
+#include "network-mgr.h"
+#include "server-status-service.h"
+
+#include "api-client.h"
+
+namespace {
+
+const char *kContentTypeForm = "application/x-www-form-urlencoded";
+const char *kAuthHeader = "Authorization";
+const char *kSeafileClientVersionHeader = "X-Seafile-Client-Version";
+
+const int kMaxRedirects = 3;
+const int kMaxHttpErrorLogLen = 300;
+
+bool shouldIgnoreRequestError(const QNetworkReply* reply)
+{
+ return reply->url().toString().contains("/api2/events");
+}
+
+QString getQueryValue(const QUrl& url, const QString& name)
+{
+ QString v;
+ v = QUrlQuery(url.query()).queryItemValue(name);
+ return QUrl::fromPercentEncoding(v.toUtf8());
+}
+
+QNetworkAccessManager *createQNAM() {
+ QNetworkAccessManager *manager = new QNetworkAccessManager(qApp);
+ NetworkManager::instance()->addWatch(manager);
+ manager->setCache(CustomizationService::instance()->diskCache());
+
+ // From: http://www.qtcentre.org/threads/37514-use-of-QNetworkAccessManager-networkAccessible
+ //
+ // QNetworkAccessManager::networkAccessible is not explicitly set when the
+ // QNetworkAccessManager is created. It is only set after the network
+ // session is initialized. The session is initialized automatically when you
+ // make a network request or you can initialize it before hand with
+ // QNetworkAccessManager::setConfiguration() or the
+ // QNetworkConfigurationManager::NetworkSessionRequired flag is set.
+ manager->setConfiguration(
+ QNetworkConfigurationManager().defaultConfiguration());
+ return manager;
+}
+
+} // namespace
+
+QNetworkAccessManager* SeafileApiClient::qnam_ = nullptr;
+void SeafileApiClient::resetQNAM()
+{
+ if (qnam_) {
+ qnam_->deleteLater();
+ }
+ qnam_ = createQNAM();
+}
+
+SeafileApiClient::SeafileApiClient(QObject *parent)
+ : QObject(parent),
+ reply_(NULL),
+ redirect_count_(0),
+ use_cache_(false)
+{
+ if (!qnam_) {
+ qnam_ = createQNAM();
+ }
+ connect(qnam_, SIGNAL(destroyed(QObject *)),
+ this, SLOT(doAbort()));
+}
+
+void SeafileApiClient::doAbort()
+{
+ if (reply_ && reply_->isRunning()) {
+ qWarning("aborting api request %s on network error", toCStr(reply_->url().toString()));
+ reply_->abort();
+ }
+}
+
+SeafileApiClient::~SeafileApiClient()
+{
+}
+
+void SeafileApiClient::prepareRequest(QNetworkRequest *req)
+{
+ if (use_cache_) {
+ req->setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
+ req->setAttribute(QNetworkRequest::CacheSaveControlAttribute, true);
+ } else {
+ req->setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork);
+ req->setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
+ }
+ if (token_.length() > 0) {
+ char buf[1024];
+ qsnprintf(buf, sizeof(buf), "Token %s", token_.toUtf8().data());
+ req->setRawHeader(kAuthHeader, buf);
+ }
+
+ foreach (const QString& key, headers_.keys()) {
+ req->setRawHeader(key.toUtf8().data(), headers_[key].toUtf8().data());
+ }
+
+ req->setRawHeader(kSeafileClientVersionHeader, STRINGIZE(SEAFILE_CLIENT_VERSION));
+}
+
+void SeafileApiClient::get(const QUrl& url)
+{
+ QNetworkRequest request(url);
+ prepareRequest(&request);
+
+ reply_ = qnam_->get(request);
+ // By default the parent object of the reply instance would be the
+ // QNetworkAccessManager, and we delete the reply in our destructor. But now
+ // we may recreate the QNetworkAccessManager when the connection status is
+ // changed, which means the reply may already have been deleted when the
+ // destructor is called. To avoid this, we explicitly set the
+ // SeafileApiClient as the parent object of the reply.
+ reply_->setParent(this);
+
+ connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+ this, SLOT(onSslErrors(const QList<QSslError>&)));
+
+ connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+}
+
+void SeafileApiClient::post(const QUrl& url, const QByteArray& data, bool is_put)
+{
+ body_ = data;
+ QNetworkRequest request(url);
+ prepareRequest(&request);
+
+ if (!headers_.contains("Content-Type")) {
+ request.setHeader(QNetworkRequest::ContentTypeHeader, kContentTypeForm);
+ }
+
+ if (is_put)
+ reply_ = qnam_->put(request, body_);
+ else
+ reply_ = qnam_->post(request, body_);
+
+ reply_->setParent(this);
+
+ connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+
+ connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+ this, SLOT(onSslErrors(const QList<QSslError>&)));
+}
+
+void SeafileApiClient::deleteResource(const QUrl& url)
+{
+ QNetworkRequest request(url);
+ prepareRequest(&request);
+
+ reply_ = qnam_->deleteResource(request);
+ reply_->setParent(this);
+
+ connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+ this, SLOT(onSslErrors(const QList<QSslError>&)));
+
+ connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+}
+
+void SeafileApiClient::onSslErrors(const QList<QSslError>& errors)
+{
+ const QUrl url = reply_->url();
+ CertsManager *mgr = seafApplet->certsManager();
+ Q_FOREACH(const QSslError &error, errors) {
+ const QSslCertificate &cert = error.certificate();
+
+ if (cert.isNull()) {
+ // The server has no ssl certificate, we do nothing and let the
+ // request fail
+ // it is a fatal error, no way to recover
+ qWarning("the certificate for %s is null", url.toString().toUtf8().data());
+ break;
+ }
+
+ QSslCertificate saved_cert = mgr->getCertificate(url.toString());
+
+ if (saved_cert.isNull()) {
+ // dump certificate information
+ qWarning() << "\n= SslError =\n" << error.errorString();
+ qWarning() << dumpCipher(reply_->sslConfiguration().sessionCipher());
+ qWarning() << dumpCertificate(cert);
+
+ // This is the first time when the client connects to the server.
+ if (seafApplet->detailedYesOrNoBox(
+ tr("<b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?"),
+ error.errorString() + "\n" + dumpCertificate(cert), 0, false)) {
+ mgr->saveCertificate(url, cert);
+ // TODO handle ssl by verifying certificate chain instead
+ reply_->ignoreSslErrors();
+ }
+ break;
+ } else if (saved_cert == cert) {
+ // The user has choosen to trust the certificate before
+ // TODO handle ssl by verifying certificate chain instead
+ reply_->ignoreSslErrors();
+ break;
+ } else {
+ // dump certificate information
+ qWarning() << "\n= SslError =\n" << error.errorString();
+ qWarning() << dumpCipher(reply_->sslConfiguration().sessionCipher());
+ qWarning() << dumpCertificate(cert);
+ qWarning() << dumpCertificate(saved_cert);
+
+ /**
+ * The cert which the user had chosen to trust has been changed. It
+ * may be either:
+ *
+ * 1. The server has changed its ssl certificate
+ * 2. The user's connection is under security attack
+ *
+ * Anyway, we'll prompt the user
+ */
+ SslConfirmDialog dialog(url, cert, saved_cert, seafApplet->mainWindow());
+ if (dialog.exec() == QDialog::Accepted) {
+ // TODO handle ssl by verifying certificate chain instead
+ reply_->ignoreSslErrors();
+ if (dialog.rememberChoice()) {
+ mgr->saveCertificate(url, cert);
+ }
+ } else {
+ reply_->abort();
+ break;
+ }
+ break;
+ }
+ }
+}
+
+void SeafileApiClient::httpRequestFinished()
+{
+ int code = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ if (code == 0 && reply_->error() != QNetworkReply::NoError) {
+ if (NetworkManager::instance()->shouldRetry(reply_->error())) {
+ qWarning("[api] network proxy error, retrying\n");
+ resendRequest(reply_->url());
+ return;
+ }
+
+ ServerStatusService::instance()->updateOnFailedRequest(reply_->url());
+ NetworkStatusDetector::instance()->setNetworkFailure(reply_->error());
+
+ if (!shouldIgnoreRequestError(reply_)) {
+ qWarning("[api] network error for %s: %s\n", toCStr(reply_->url().toString()),
+ reply_->errorString().toUtf8().data());
+ }
+ emit networkError(reply_->error(), reply_->errorString());
+ return;
+ }
+
+ ServerStatusService::instance()->updateOnSuccessfullRequest(reply_->url());
+ NetworkStatusDetector::instance()->setNetworkSuccess();
+
+ if (handleHttpRedirect()) {
+ return;
+ }
+
+ if ((code / 100) == 4 || (code / 100) == 5) {
+ if (!shouldIgnoreRequestError(reply_)) {
+ QByteArray content = reply_->readAll();
+ qWarning("request failed for %s: %s\n",
+ reply_->url().toString().toUtf8().data(),
+ content.left(kMaxHttpErrorLogLen).data());
+ if (content.length() > kMaxHttpErrorLogLen) {
+ qDebug("request failed for %s: %s\n",
+ reply_->url().toString().toUtf8().data(),
+ content.data());
+ }
+ }
+ emit requestFailed(code);
+ return;
+ }
+
+ emit requestSuccess(*reply_);
+}
+
+// Return true if the request is redirected and request is resended.
+bool SeafileApiClient::handleHttpRedirect()
+{
+ QVariant redirect_attr = reply_->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect_attr.isNull()) {
+ return false;
+ }
+
+ QUrl redirect_url = redirect_attr.toUrl();
+ if (redirect_url.isRelative()) {
+ redirect_url = reply_->url().resolved(redirect_url);
+ }
+
+ // printf("redirect to %s (from %s)\n", redirect_url.toString().toUtf8().data(),
+ // reply_->url().toString().toUtf8().data());
+ if (reply_->operation() == QNetworkAccessManager::PostOperation) {
+ // XXX: Special case for rename/move file api, which returns 301 on
+ // success. We need to distinguish that from a normal 301 redirect.
+ // (In contrast, Rename/move dir api returns 200 on success).
+ if (redirect_url.path().contains(QRegExp("/api2/repos/[^/]+/file/"))) {
+ QString old_name = getQueryValue(reply_->url(), "p");
+ QString new_name = getQueryValue(redirect_url, "p");
+ // Only treat it as a rename file success when old and new are different
+ if (!old_name.isEmpty() && !new_name.isEmpty() && old_name != new_name) {
+ // printf ("get 301 rename file success, old_name: %s, new_name: %s\n",
+ // toCStr(old_name), toCStr(new_name));
+ return false;
+ }
+ }
+ }
+
+
+ if (redirect_count_++ > kMaxRedirects) {
+ // simply treat too many redirects as server side error
+ emit requestFailed(500);
+ qWarning("too many redirects for %s\n",
+ reply_->url().toString().toUtf8().data());
+ return true;
+ }
+
+ resendRequest(redirect_url);
+
+ return true;
+}
+
+void SeafileApiClient::resendRequest(const QUrl& url)
+{
+ switch (reply_->operation()) {
+ case QNetworkAccessManager::GetOperation:
+ reply_->deleteLater();
+ get(url);
+ break;
+ case QNetworkAccessManager::PostOperation:
+ post(url, body_, false);
+ break;
+ case QNetworkAccessManager::PutOperation:
+ post(url, body_, true);
+ break;
+ case QNetworkAccessManager::DeleteOperation:
+ reply_->deleteLater();
+ deleteResource(url);
+ break;
+ default:
+ reply_->deleteLater();
+ qWarning() << "unsupported operation" << reply_->operation()
+ << "to" << url.toString()
+ << "from" << reply_->url().toString();
+ break;
+ }
+}
+
+void SeafileApiClient::setHeader(const QString& key, const QString& value)
+{
+ headers_[key] = value;
+}
--- /dev/null
+#ifndef SEAFILE_API_CLIENT_H
+#define SEAFILE_API_CLIENT_H
+
+#include <QHash>
+#include <QString>
+#include <QObject>
+#include <QNetworkReply>
+
+#include "account.h"
+#include "server-repo.h"
+
+class QNetworkAccessManager;
+class QSslError;
+
+/**
+ * SeafileApiClient handles the underlying api mechanism
+ */
+class SeafileApiClient : public QObject {
+ Q_OBJECT
+
+public:
+ SeafileApiClient(QObject *parent=0);
+ ~SeafileApiClient();
+ void setToken(const QString& token) { token_ = token; };
+ void setHeader(const QString& key, const QString& value);
+ void get(const QUrl& url);
+ void post(const QUrl& url, const QByteArray& body, bool is_put);
+ void deleteResource(const QUrl& url);
+ void setUseCache(bool use_cache) { use_cache_ = use_cache; }
+
+ const QNetworkReply* reply() const { return reply_; }
+
+ static QNetworkAccessManager *qnam_;
+ static void resetQNAM();
+
+signals:
+ void requestSuccess(QNetworkReply& reply);
+ void requestFailed(int code);
+ void networkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+
+private slots:
+ void httpRequestFinished();
+ void onSslErrors(const QList<QSslError>& errors);
+ void doAbort();
+
+private:
+ Q_DISABLE_COPY(SeafileApiClient)
+
+ bool handleHttpRedirect();
+ bool handleRedirectForNonGetRequest();
+ void prepareRequest(QNetworkRequest *req);
+
+ void resendRequest(const QUrl& url);
+
+ QString token_;
+
+ QByteArray body_;
+
+ QNetworkReply *reply_;
+
+ int redirect_count_;
+ bool use_cache_;
+
+ QHash<QString, QString> headers_;
+};
+
+#endif // SEAFILE_API_CLIENT_H
--- /dev/null
+#include "api-error.h"
+
+ApiError::ApiError()
+{
+ ssl_reply_ = NULL;
+}
+
+ApiError ApiError::fromNetworkError(const QNetworkReply::NetworkError& network_error,
+ const QString& network_error_string)
+{
+ ApiError error;
+
+ error.type_ = NETWORK_ERROR;
+ error.network_error_ = network_error;
+ error.network_error_string_ = network_error_string;
+
+ return error;
+}
+
+ApiError ApiError::fromSslErrors(QNetworkReply *reply, const QList<QSslError>& ssl_errors)
+{
+ ApiError error;
+
+ error.type_ = SSL_ERROR;
+ error.ssl_reply_ = reply;
+ error.ssl_errors_ = ssl_errors;
+
+ return error;
+}
+
+ApiError ApiError::fromHttpError(int code)
+{
+ ApiError error;
+
+ error.type_ = HTTP_ERROR;
+ error.http_error_code_ = code;
+
+ return error;
+}
+
+ApiError ApiError::fromJsonError()
+{
+ ApiError error;
+
+ error.type_ = HTTP_ERROR;
+ // 500 internal server error
+ error.http_error_code_ = 500;
+
+ return error;
+}
+
+QString ApiError::toString() const {
+ switch (type_) {
+ case SSL_ERROR:
+ return QObject::tr("SSL Error");
+ case NETWORK_ERROR:
+ return QObject::tr("Network Error: %1").arg(network_error_string_);
+ case HTTP_ERROR:
+ if (http_error_code_ == 443) {
+ return QObject::tr("The storage quota has been used up");
+ } else {
+ return QObject::tr("Server Error");
+ }
+ default:
+ // impossible
+ break;
+ }
+
+ return "";
+}
+
+ApiError ApiError::NoError() {
+ ApiError error;
+ error.type_ = NOT_AN_ERROR;
+ return error;
+}
+
+bool ApiError::operator==(const ApiError& other)
+{
+ if (type_ != other.type_) {
+ return false;
+ }
+
+ bool same;
+ switch (type_) {
+ case NOT_AN_ERROR:
+ same = true;
+ break;
+ case HTTP_ERROR:
+ same = http_error_code_ == other.http_error_code_;
+ break;
+ case NETWORK_ERROR:
+ same = network_error_ == other.network_error_;
+ break;
+ case SSL_ERROR:
+ same = ssl_errors_ == other.ssl_errors_;
+ break;
+ }
+
+ return same;
+}
--- /dev/null
+#ifndef SEAFILE_API_ERROR_H
+#define SEAFILE_API_ERROR_H
+
+#include <QString>
+#include <QNetworkReply>
+#include <QList>
+#include <QSslError>
+
+#include "server-repo.h"
+
+class QNetworkAccessManager;
+class QByteArray;
+
+/**
+ * Error info in an api request.
+ */
+class ApiError {
+public:
+ enum ErrorType {
+ NOT_AN_ERROR = 0,
+ // network error, like connection refused
+ NETWORK_ERROR,
+ // ssl error, like invalid ssl certificate
+ SSL_ERROR,
+ // http error, like 4xx, 5xx
+ HTTP_ERROR,
+ };
+
+ static ApiError fromNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+ static ApiError fromSslErrors(QNetworkReply *reply, const QList<QSslError>& errors);
+ static ApiError fromHttpError(int code);
+ static ApiError fromJsonError();
+ static ApiError NoError();
+
+ // accessors
+ ErrorType type() const { return type_; }
+
+ const QNetworkReply::NetworkError& networkError() const { return network_error_; }
+ const QString& networkErrorString() const { return network_error_string_; }
+
+ QNetworkReply *sslReply() const { return ssl_reply_; }
+ const QList<QSslError>& sslErrors() const { return ssl_errors_; }
+
+ int httpErrorCode() const { return http_error_code_; }
+
+ QString toString() const;
+
+ bool operator==(const ApiError& other);
+
+ bool operator!=(const ApiError& other) {
+ return !(*this == other);
+ }
+
+private:
+ ApiError();
+
+ ErrorType type_;
+
+ int http_error_code_;
+
+ QNetworkReply::NetworkError network_error_;
+ QString network_error_string_;
+
+ QNetworkReply *ssl_reply_;
+ QList<QSslError> ssl_errors_;
+};
+
+#endif // SEAFILE_API_ERROR_H
--- /dev/null
+#include <QtGlobal>
+#include <QtNetwork>
+#include <QUrlQuery>
+
+#include "utils/utils.h"
+#include "api-client.h"
+#include "api-error.h"
+
+#include "api-request.h"
+
+SeafileApiRequest::SeafileApiRequest(const QUrl& url, Method method,
+ const QString& token)
+ : url_(url),
+ method_(method),
+ token_(token)
+{
+ api_client_ = new SeafileApiClient;
+}
+
+SeafileApiRequest::~SeafileApiRequest()
+{
+ if (api_client_) {
+ api_client_->deleteLater();
+ api_client_ = nullptr;
+ }
+}
+
+void SeafileApiRequest::setUrlParam(const QString& name, const QString& value)
+{
+ params_[name] = value;
+}
+
+void SeafileApiRequest::setFormParam(const QString& name, const QString& value)
+{
+ if (method_ != METHOD_PUT && method_ != METHOD_POST) {
+ qWarning("warning: calling setFormParam on a request with method %d\n", method_);
+ }
+ form_params_[name] = value;
+}
+
+void SeafileApiRequest::setRequestBody(const QByteArray& content)
+{
+ if (method_ != METHOD_PUT && method_ != METHOD_POST) {
+ qWarning("warning: calling setRequestBody on a request with method %d\n", method_);
+ }
+ post_data_ = content;
+}
+
+void SeafileApiRequest::setUseCache(bool use_cache)
+{
+ api_client_->setUseCache(use_cache);
+}
+
+void SeafileApiRequest::setHeader(const QString& key, const QString& value)
+{
+ api_client_->setHeader(key, value);
+}
+
+void SeafileApiRequest::send()
+{
+ if (token_.size() > 0) {
+ api_client_->setToken(token_);
+ }
+
+ if (!params_.isEmpty()) {
+ url_ = ::includeQueryParams(url_, params_);
+ }
+
+ QByteArray post_data;
+
+ switch (method_) {
+ case METHOD_GET:
+ api_client_->get(url_);
+ break;
+ case METHOD_DELETE:
+ api_client_->deleteResource(url_);
+ break;
+ case METHOD_POST:
+ case METHOD_PUT:
+ if (!post_data_.isEmpty()) {
+ api_client_->post(url_, post_data_, method_ == METHOD_PUT);
+ } else {
+ post_data = ::buildFormData(form_params_);
+ api_client_->post(url_, post_data, method_ == METHOD_PUT);
+ }
+ break;
+ default:
+ qWarning("unknown method %d\n", method_);
+ return;
+ }
+
+ post_data_.clear();
+ connect(api_client_, SIGNAL(requestSuccess(QNetworkReply&)),
+ this, SLOT(requestSuccess(QNetworkReply&)));
+
+ connect(api_client_, SIGNAL(networkError(const QNetworkReply::NetworkError&, const QString&)),
+ this, SLOT(onNetworkError(const QNetworkReply::NetworkError&, const QString&)));
+
+ connect(api_client_, SIGNAL(requestFailed(int)),
+ this, SLOT(onHttpError(int)));
+}
+
+void SeafileApiRequest::onHttpError(int code)
+{
+ emit failed(ApiError::fromHttpError(code));
+}
+
+void SeafileApiRequest::onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string)
+{
+ emit failed(ApiError::fromNetworkError(error, error_string));
+}
+
+
+json_t* SeafileApiRequest::parseJSON(QNetworkReply &reply, json_error_t *error)
+{
+ QByteArray raw = reply.readAll();
+ //qWarning("\n%s\n", raw.data());
+ json_t *root = json_loads(raw.data(), 0, error);
+ return root;
+}
+
+const QNetworkReply* SeafileApiRequest::reply() const
+{
+ return api_client_->reply();
+}
--- /dev/null
+#ifndef SEAFILE_API_REQUEST_H
+#define SEAFILE_API_REQUEST_H
+
+#include <jansson.h>
+
+#include <QObject>
+#include <QUrl>
+#include <QMap>
+#include <QPair>
+#include <QList>
+#include <QNetworkReply>
+#include <QHash>
+
+class SeafileApiClient;
+class QSslError;
+class ApiError;
+
+/**
+ * Abstract base class for all types of api requests
+ */
+class SeafileApiRequest : public QObject {
+ Q_OBJECT
+
+public:
+ virtual ~SeafileApiRequest();
+
+ const QUrl& url() const { return url_; }
+
+ // set param k-v pair which appears in query params
+ void setUrlParam(const QString& name, const QString& value);
+ // set param k-v pair which appears in url-encoded form
+ void setFormParam(const QString& name, const QString& value);
+ // set http request body directly
+ void setRequestBody(const QByteArray& content);
+ // useful for static resources like images
+ void setUseCache(bool use_cache);
+
+ void setHeader(const QString& key, const QString& value);
+
+ virtual void send();
+
+ const QNetworkReply* reply() const;
+
+signals:
+ void failed(const ApiError& error);
+
+protected slots:
+ virtual void requestSuccess(QNetworkReply& reply) = 0;
+ void onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+ void onHttpError(int);
+
+protected:
+ enum Method {
+ // post action, passing urlParam and formParam
+ METHOD_POST,
+ // get action, passing urlParam only
+ METHOD_GET,
+ // put action, passing urlParam and formParam
+ METHOD_PUT,
+ // delete action, passing urlParam only
+ METHOD_DELETE
+ };
+
+ SeafileApiRequest(const QUrl& url,
+ const Method method,
+ const QString& token = QString());
+
+ json_t* parseJSON(QNetworkReply &reply, json_error_t *error);
+
+ // Used with QScopedPointer for json_t
+ struct JsonPointerCustomDeleter {
+ static inline void cleanup(json_t *json) {
+ json_decref(json);
+ }
+ };
+
+private:
+ Q_DISABLE_COPY(SeafileApiRequest)
+
+ QUrl url_;
+ QHash<QString, QString> params_;
+ QHash<QString, QString> form_params_;
+ Method method_;
+ QString token_;
+ QByteArray post_data_;
+
+ SeafileApiClient* api_client_;
+};
+
+#endif // SEAFILE_API_REQUEST_H
--- /dev/null
+#include <glib.h>
+#include <glib-object.h>
+
+#include "commit-details.h"
+
+
+namespace {
+
+QString getStringFromJsonArray(const json_t *array, size_t index)
+{
+ return QString::fromUtf8(json_string_value(json_array_get(array, index)));
+}
+
+void processFileList(const json_t *json, const char *key, std::vector<QString> *files)
+{
+ json_t *array = json_object_get(json, key);
+ if (array) {
+ for (int i = 0, n = json_array_size(array); i < n; i++) {
+ QString name = getStringFromJsonArray(array, i);
+ files->push_back(name);
+ }
+ }
+}
+
+} // namespace
+
+
+CommitDetails CommitDetails::fromJSON(const json_t *json, json_error_t */* error */)
+{
+ CommitDetails details;
+
+ processFileList(json, "added_files", &details.added_files);
+ processFileList(json, "deleted_files", &details.deleted_files);
+ processFileList(json, "modified_files", &details.modified_files);
+
+ processFileList(json, "added_dirs", &details.added_dirs);
+ processFileList(json, "deleted_dirs", &details.deleted_dirs);
+
+ // process renamed files
+ json_t *array = json_object_get(json, "renamed_files");
+ if (array) {
+ for (int i = 0, n = json_array_size(array); i < n; i += 2) {
+ QString before_rename = getStringFromJsonArray(array, i);
+ QString after_rename = getStringFromJsonArray(array, i + 1);
+ std::pair<QString, QString> pair(before_rename, after_rename);
+ details.renamed_files.push_back(pair);
+ }
+ }
+
+ return details;
+}
+
+
+CommitDetails CommitDetails::fromObjList(const GList *objlist)
+{
+ CommitDetails details;
+
+ for (const GList *ptr = objlist; ptr; ptr = ptr->next) {
+ GObject *obj = (GObject *)(ptr->data);
+ char *c_status = NULL;
+ char *c_name = NULL;
+ char *c_new_name = NULL;
+ g_object_get(obj,
+ "status",
+ &c_status,
+ "name",
+ &c_name,
+ "new_name",
+ &c_new_name,
+ NULL);
+
+ QString status(c_status);
+ QString name(c_name);
+ QString new_name(c_new_name);
+
+ // printf("%s\n%s\n%s\n",
+ // status.toUtf8().data(),
+ // name.toUtf8().data(),
+ // new_name.toUtf8().data());
+
+ if (status == "add") {
+ details.added_files.push_back(name);
+ } else if (status == "del") {
+ details.deleted_files.push_back(name);
+ } else if (status == "mov") {
+ details.renamed_files.push_back({name, new_name});
+ } else if (status == "mod") {
+ details.modified_files.push_back(name);
+ } else if (status == "newdir") {
+ details.added_dirs.push_back(name);
+ } else if (status == "deldir") {
+ details.deleted_dirs.push_back(name);
+ }
+ }
+
+ return details;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_API_COMMIT_DETAILS_H
+#define SEAFILE_CLIENT_API_COMMIT_DETAILS_H
+
+#include <jansson.h>
+
+#include <vector>
+#include <utility>
+
+#include <QString>
+#include <QMetaType>
+
+struct _GList;
+
+class CommitDetails {
+public:
+ std::vector<QString> added_files, deleted_files, modified_files, added_dirs, deleted_dirs;
+
+ // renamed or moved files
+ std::vector<std::pair<QString, QString> > renamed_files;
+
+ static CommitDetails fromJSON(const json_t*, json_error_t *error);
+ static CommitDetails fromObjList(const _GList *objlist);
+};
+
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(CommitDetails)
+
+#endif // SEAFILE_CLIENT_API_COMMIT_DETAILS_H
--- /dev/null
+#include <QHash>
+#include "contact-share-info.h"
+
+uint qHash(const SeafileUser& user, uint seed) {
+ return qHash(user.email, seed);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
+#define SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
+
+#include <QMetaType>
+#include <QString>
+
+struct SeafileGroup {
+ int id;
+ QString name;
+ QString owner;
+ bool isValid() const { return !name.isEmpty(); }
+};
+
+struct SeafileUser {
+ QString avatar_url;
+ QString email;
+ // Optional fields;
+ QString contact_email;
+ QString name;
+
+ bool operator==(const SeafileUser& rhs) const {
+ return rhs.email == email;
+ }
+
+ QString getDisplayEmail() const {
+ return !contact_email.isEmpty() ? contact_email : email;
+ }
+
+ bool isValid() const { return !email.isEmpty(); }
+};
+
+uint qHash(const SeafileUser& user, uint seed=0);
+
+enum SharePermission {
+ READ_WRITE,
+ READ_ONLY,
+};
+
+
+enum ShareType {
+ SHARE_TO_USER,
+ SHARE_TO_GROUP,
+};
+
+
+inline SharePermission permissionfromString(const QString& s)
+{
+ return s == "r" ? READ_ONLY : READ_WRITE;
+}
+
+inline ShareType shareTypeFromString(const QString& s)
+{
+ return s == "group" ? SHARE_TO_GROUP : SHARE_TO_USER;
+}
+
+struct UserShareInfo {
+ SharePermission permission;
+ SeafileUser user;
+};
+
+struct GroupShareInfo {
+ SharePermission permission;
+ SeafileGroup group;
+};
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(SeafileGroup)
+Q_DECLARE_METATYPE(SeafileUser)
+Q_DECLARE_METATYPE(UserShareInfo)
+Q_DECLARE_METATYPE(GroupShareInfo)
+
+#endif // SEAFILE_CLIENT_CONTACT_SHARE_INFO_H
--- /dev/null
+#include <jansson.h>
+
+#include <vector>
+
+#include "utils/translate-commit-desc.h"
+
+
+#include "event.h"
+
+#include <QDateTime>
+
+namespace {
+
+QString getStringFromJson(const json_t *json, const char* key)
+{
+ return QString::fromUtf8(json_string_value(json_object_get(json, key)));
+}
+
+const char *kEventTypeRepoCreate = "repo-create";
+const char *kEventTypeRepoDelete = "repo-delete";
+
+} // namespace
+
+
+SeafEvent SeafEvent::fromJSON(const json_t *json, json_error_t */* error */)
+{
+ SeafEvent event;
+
+ event.author = getStringFromJson(json, "author");
+ if (event.author.isEmpty()) {
+ event.author = "anonymous";
+ event.anonymous = true;
+ } else {
+ event.anonymous = false;
+ }
+
+ event.nick = getStringFromJson(json, "nick");
+ if (event.nick.isEmpty()) {
+ event.nick = "anonymous";
+ }
+
+ event.repo_id = getStringFromJson(json, "repo_id");
+ event.repo_name = getStringFromJson(json, "repo_name");
+
+ event.commit_id = getStringFromJson(json, "commit_id");
+ event.etype = getStringFromJson(json, "etype");
+ event.desc = getStringFromJson(json, "desc");
+
+ event.timestamp = json_integer_value(json_object_get(json, "time"));
+
+ if (event.etype == kEventTypeRepoCreate) {
+ event.desc = QObject::tr("Created library \"%1\"").arg(event.repo_name);
+ } else if (event.etype == kEventTypeRepoDelete) {
+ event.desc = QObject::tr("Deleted library \"%1\"").arg(event.repo_name);
+ }
+
+ event.desc = translateCommitDesc(event.desc);
+
+ // For testing long lines of event description.
+ // event.desc += event.desc + event.desc;
+
+ return event;
+}
+
+// parser seafile new file activities json
+SeafEvent SeafEvent::fromJSONV2(const json_t *json, json_error_t */* error */)
+{
+ SeafEvent event;
+
+ event.author = getStringFromJson(json, "author_email");
+ if (event.author.isEmpty()) {
+ event.author = "anonymous";
+ event.anonymous = true;
+ } else {
+ event.anonymous = false;
+ }
+
+ event.nick = getStringFromJson(json, "author_name");
+ if (event.nick.isEmpty()) {
+ event.nick = "anonymous";
+ }
+
+ event.repo_id = getStringFromJson(json, "repo_id");
+ event.repo_name = getStringFromJson(json, "repo_name");
+ event.commit_id = getStringFromJson(json, "commit_id");
+ event.etype = getStringFromJson(json, "op_type");
+ event.is_use_new_activities_api = true;
+
+ QString time = getStringFromJson(json, "time");
+ event.timestamp = QDateTime::fromString(time, Qt::ISODate).toMSecsSinceEpoch() / 1000;
+
+ QString path = getStringFromJson(json, "path");
+ QString file_name = getStringFromJson(json, "name");
+ QString obj_type = getStringFromJson(json, "obj_type");
+ QString old_name = getStringFromJson(json, "old_name");
+ QString old_path = getStringFromJson(json, "old_path");
+ QString old_repo_name = getStringFromJson(json, "old_repo_name");
+ bool ok;
+ int clean_trash_days = getStringFromJson(json, "days").toInt(&ok);
+
+ QString out_obj_desc, out_op_desc;
+ translateCommitDescV2(path, file_name, event.repo_name, obj_type,
+ event.etype, old_repo_name, old_path,
+ old_name, clean_trash_days, &out_obj_desc,
+ &out_op_desc);
+ event.desc = out_obj_desc;
+ event.op_desc = out_op_desc;
+
+ return event;
+}
+
+std::vector<SeafEvent> SeafEvent::listFromJSON(const json_t *json, json_error_t *error, bool is_use_new_json_parser)
+{
+ std::vector<SeafEvent> events;
+
+ for (size_t i = 0; i < json_array_size(json); i++) {
+ SeafEvent event;
+ if (!is_use_new_json_parser) {
+ event = fromJSON(json_array_get(json, i), error);
+ } else {
+ event = fromJSONV2(json_array_get(json, i), error);
+ }
+
+ events.push_back(event);
+ }
+
+ return events;
+}
+
+QString SeafEvent::toString() const
+{
+ return QString("type=\"%1\",author=\"%2\",repo_name=\"%3\",desc=\"%4\",commit=\"%5\"")
+ .arg(etype).arg(author).arg(repo_name).arg(desc).arg(commit_id);
+}
+
+bool SeafEvent::isDetailsDisplayable() const
+{
+ if (commit_id.isEmpty()) {
+ return false;
+ }
+ // TODO: determine if there are files change in this commit
+ return true;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_API_EVENT_H
+#define SEAFILE_CLIENT_API_EVENT_H
+
+#include <jansson.h>
+#include <vector>
+
+#include <QObject>
+#include <QString>
+#include <QMetaType>
+
+class SeafEvent {
+public:
+ QString author;
+ QString nick;
+ QString repo_id;
+ QString repo_name;
+ QString etype;
+ QString commit_id;
+ QString desc;
+ QString op_desc;
+ qint64 timestamp;
+ bool is_use_new_activities_api;
+
+ // true for events like a file upload by unregistered user from a
+ // uploadable link
+ bool anonymous;
+
+ bool isDetailsDisplayable() const;
+
+ static SeafEvent fromJSON(const json_t*, json_error_t *error);
+ static SeafEvent fromJSONV2(const json_t*, json_error_t *error);
+ static std::vector<SeafEvent> listFromJSON(const json_t*, json_error_t *json, bool is_use_new_json_parser = false);
+
+ QString toString() const;
+};
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(SeafEvent)
+
+#endif // SEAFILE_CLIENT_API_EVENT_H
--- /dev/null
+#include <jansson.h>
+
+#include <QScopedPointer>
+#include <QtNetwork>
+
+#include "account.h"
+
+#include "api-error.h"
+#include "commit-details.h"
+#include "event.h"
+#include "repo-service.h"
+#include "rpc/rpc-client.h"
+#include "seafile-applet.h"
+#include "server-repo.h"
+#include "starred-file.h"
+#include "utils/api-utils.h"
+#include "utils/json-utils.h"
+#include "utils/utils.h"
+#include "account-mgr.h"
+
+#include "requests.h"
+
+namespace
+{
+const char* kApiPingUrl = "api2/ping/";
+const char* kApiLoginUrl = "api2/auth-token/";
+const char* kListReposUrl = "api2/repos/";
+const char* kCreateRepoUrl = "api2/repos/";
+const char* kGetRepoUrl = "api2/repos/%1/";
+const char* kCreateSubrepoUrl = "api2/repos/%1/dir/sub_repo/";
+const char* kUnseenMessagesUrl = "api2/unseen_messages/";
+const char* kDefaultRepoUrl = "api2/default-repo/";
+const char* kStarredFilesUrl = "api2/starredfiles/";
+const char* kStarredItemsUrl = "api/v2.1/starred-items/";
+const char* kGetEventsUrl = "api2/events/";
+const char* kCommitDetailsUrl = "api2/repo_history_changes/";
+const char* kAvatarUrl = "api2/avatars/user/";
+const char* kSetRepoPasswordUrl = "api2/repos/";
+const char* kServerInfoUrl = "api2/server-info/";
+const char* kLogoutDeviceUrl = "api2/logout-device/";
+const char* kGetRepoTokensUrl = "api2/repo-tokens/";
+const char* kGetLoginTokenUrl = "api2/client-login/";
+const char* kFileSearchUrl = "api2/search/";
+const char* kAccountInfoUrl = "api2/account/info/";
+const char* kDirSharedItemsUrl = "api2/repos/%1/dir/shared_items/";
+const char* kRepoSharedUrl = "api2/beshared-repos/%1/";
+const char* kFetchGroupsAndContactsUrl = "api2/groupandcontacts/";
+const char* kFetchGroupsUrl = "api2/groups/";
+const char* kRemoteWipeReportUrl = "api2/device-wiped/";
+const char* kSearchUsersUrl = "api2/search-user/";
+const char* kGetThumbnailUrl = "api2/repos/%1/thumbnail/";
+const char* kCreateFileUploadLink = "api/v2.1/upload-links/";
+
+const char* kGetFileActivitiesUrl = "api/v2.1/activities/";
+} // namespace
+
+
+PingServerRequest::PingServerRequest(const QUrl& serverAddr)
+
+ : SeafileApiRequest(::urlJoin(serverAddr, kApiPingUrl),
+ SeafileApiRequest::METHOD_GET)
+{
+}
+
+void PingServerRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+/**
+ * LoginRequest
+ */
+LoginRequest::LoginRequest(const QUrl& serverAddr,
+ const QString& username,
+ const QString& password,
+ const QString& computer_name)
+
+ : SeafileApiRequest(::urlJoin(serverAddr, kApiLoginUrl),
+ SeafileApiRequest::METHOD_POST)
+{
+ setFormParam("username", username);
+ setFormParam("password", password);
+
+ QHash<QString, QString> params = ::getSeafileLoginParams(computer_name);
+ foreach (const QString& key, params.keys()) {
+ setFormParam(key, params[key]);
+ }
+}
+
+void LoginRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QString s2fa_token = reply.rawHeader("X-SEAFILE-S2FA");
+ const char* token =
+ json_string_value(json_object_get(json.data(), "token"));
+ if (token == NULL) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ emit success(token, s2fa_token);
+}
+
+
+/**
+ * ListReposRequest
+ */
+ListReposRequest::ListReposRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kListReposUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+}
+
+void ListReposRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("ListReposRequest:failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ std::vector<ServerRepo> repos =
+ ServerRepo::listFromJSON(json.data(), &error);
+ emit success(repos);
+}
+
+
+/**
+ * DownloadRepoRequest
+ */
+DownloadRepoRequest::DownloadRepoRequest(const Account& account,
+ const QString& repo_id,
+ bool read_only)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl("api2/repos/" + repo_id + "/download-info/"),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ read_only_(read_only)
+{
+}
+
+RepoDownloadInfo RepoDownloadInfo::fromDict(QMap<QString, QVariant>& dict,
+ const QUrl& url_in,
+ bool read_only)
+{
+ RepoDownloadInfo info;
+ info.repo_version = dict["repo_version"].toInt();
+ info.email = dict["email"].toString();
+ info.token = dict["token"].toString();
+ info.repo_id = dict["repo_id"].toString();
+ info.repo_name = dict["repo_name"].toString();
+ info.encrypted = dict["encrypted"].toInt();
+ info.magic = dict["magic"].toString();
+ info.random_key = dict["random_key"].toString();
+ info.enc_version = dict.value("enc_version", 1).toInt();
+ info.readonly = read_only;
+
+ QUrl url = url_in;
+ url.setPath("/");
+
+ QString salt = dict.value("salt").toString();
+ QMap<QString, QVariant> map;
+ map.insert("is_readonly", read_only ? 1 : 0);
+ map.insert("server_url", url.toString());
+ map.insert("repo_salt", salt);
+
+ info.more_info = ::mapToJson(map);
+
+ return info;
+}
+
+void DownloadRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+ RepoDownloadInfo info = RepoDownloadInfo::fromDict(dict, url(), read_only_);
+
+ emit success(info);
+}
+
+/**
+ * GetRepoRequest
+ */
+GetRepoRequest::GetRepoRequest(const Account& account, const QString& repoid)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetRepoUrl).arg(repoid)),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ repoid_(repoid)
+{
+}
+
+void GetRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ ServerRepo repo = ServerRepo::fromJSON(root, &error);
+
+ emit success(repo);
+}
+
+/**
+ * CreateRepoRequest
+ */
+CreateRepoRequest::CreateRepoRequest(const Account& account,
+ const QString& name,
+ const QString& desc,
+ const QString& passwd)
+ : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
+ SeafileApiRequest::METHOD_POST,
+ account.token)
+{
+ setFormParam(QString("name"), name);
+ setFormParam(QString("desc"), desc);
+ if (!passwd.isNull()) {
+ qWarning("Encrypted repo");
+ setFormParam(QString("passwd"), passwd);
+ }
+}
+
+CreateRepoRequest::CreateRepoRequest(const Account& account,
+ const QString& name,
+ const QString& desc,
+ int enc_version,
+ const QString& repo_id,
+ const QString& magic,
+ const QString& random_key)
+ : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
+ SeafileApiRequest::METHOD_POST,
+ account.token)
+{
+ setFormParam("name", name);
+ setFormParam("desc", desc);
+ setFormParam("enc_version", QString::number(enc_version));
+ setFormParam("repo_id", repo_id);
+ setFormParam("magic", magic);
+ setFormParam("random_key", random_key);
+}
+
+CreateRepoRequest::CreateRepoRequest(const Account& account,
+ const QString& name,
+ const QString& desc,
+ int enc_version,
+ const QString& repo_id,
+ const QString& magic,
+ const QString& random_key,
+ const QString& salt)
+ : SeafileApiRequest(account.getAbsoluteUrl(kCreateRepoUrl),
+ SeafileApiRequest::METHOD_POST,
+ account.token)
+{
+ setFormParam("name", name);
+ setFormParam("desc", desc);
+ setFormParam("enc_version", QString::number(enc_version));
+ setFormParam("repo_id", repo_id);
+ setFormParam("magic", magic);
+ setFormParam("random_key", random_key);
+ setFormParam("salt", salt);
+}
+
+void CreateRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ RepoDownloadInfo info = RepoDownloadInfo::fromDict(dict, url(), false);
+
+ emit success(info);
+}
+
+/**
+ * CreateSubrepoRequest
+ */
+CreateSubrepoRequest::CreateSubrepoRequest(const Account& account,
+ const QString& name,
+ const QString& repoid,
+ const QString& path,
+ const QString& passwd)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kCreateSubrepoUrl).arg(repoid)),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+ setUrlParam(QString("p"), path);
+ setUrlParam(QString("name"), name);
+ if (!passwd.isNull()) {
+ setUrlParam(QString("password"), passwd);
+ }
+}
+
+void CreateSubrepoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+ emit success(dict["sub_repo_id"].toString());
+}
+
+/**
+ * GetUnseenSeahubNotificationsRequest
+ */
+GetUnseenSeahubNotificationsRequest::GetUnseenSeahubNotificationsRequest(
+ const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kUnseenMessagesUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+}
+
+void GetUnseenSeahubNotificationsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning(
+ "GetUnseenSeahubNotificationsRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> ret = mapFromJSON(root, &error);
+
+ if (!ret.contains("count")) {
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ int count = ret.value("count").toInt();
+ emit success(count);
+}
+
+GetDefaultRepoRequest::GetDefaultRepoRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+}
+
+void GetDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+ if (!dict.contains("exists")) {
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ bool exists = dict.value("exists").toBool();
+ if (!exists) {
+ emit success(false, "");
+ return;
+ }
+
+ if (!dict.contains("repo_id")) {
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QString repo_id = dict.value("repo_id").toString();
+
+ emit success(true, repo_id);
+}
+
+
+CreateDefaultRepoRequest::CreateDefaultRepoRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kDefaultRepoUrl),
+ SeafileApiRequest::METHOD_POST,
+ account.token)
+{
+}
+
+void CreateDefaultRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("CreateDefaultRepoRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+ if (!dict.contains("repo_id")) {
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ emit success(dict.value("repo_id").toString());
+}
+
+GetStarredFilesRequest::GetStarredFilesRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kStarredFilesUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+}
+
+void GetStarredFilesRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetStarredFilesRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ std::vector<StarredItem> files =
+ StarredItem::listFromJSON(json.data(), &error);
+ emit success(files);
+}
+
+GetStarredFilesRequestV2::GetStarredFilesRequestV2(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kStarredItemsUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+}
+
+void GetStarredFilesRequestV2::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetStarredItemsRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ json_t* array = json_object_get(json.data(), "starred_item_list");
+ std::vector<StarredItem> files =
+ StarredItem::listFromJSON(array, &error, true);
+ emit success(files);
+}
+
+// Seafile get file activities api v2.1
+// page default value is 1
+// perpage defult value is 25
+// avatar size defult value is 72, old api is 36
+GetEventsRequestV2::GetEventsRequestV2(const Account& account, int page, int perpage, int avatar_size)
+ : SeafileApiRequest(account.getAbsoluteUrl(kGetFileActivitiesUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+ setUrlParam("page", QString::number(page));
+ setUrlParam("avatar_size", QString::number(avatar_size));
+}
+
+void GetEventsRequestV2::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetEventsRequestV2: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ json_t* array = json_object_get(json.data(), "events");
+ std::vector<SeafEvent> events = SeafEvent::listFromJSON(array, &error, true);
+
+ emit success(events);
+}
+
+GetEventsRequest::GetEventsRequest(const Account& account, int start)
+ : SeafileApiRequest(account.getAbsoluteUrl(kGetEventsUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+ if (start > 0) {
+ setUrlParam("start", QString::number(start));
+ }
+}
+
+void GetEventsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetEventsRequest: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ bool more = false;
+ int more_offset = -1;
+
+ json_t* array = json_object_get(json.data(), "events");
+ std::vector<SeafEvent> events = SeafEvent::listFromJSON(array, &error);
+
+ more = json_is_true(json_object_get(json.data(), "more"));
+ if (more) {
+ more_offset =
+ json_integer_value(json_object_get(json.data(), "more_offset"));
+ }
+
+ emit success(events, more_offset);
+}
+
+GetCommitDetailsRequest::GetCommitDetailsRequest(const Account& account,
+ const QString& repo_id,
+ const QString& commit_id)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(kCommitDetailsUrl + repo_id + "/"),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+ setUrlParam("commit_id", commit_id);
+}
+
+void GetCommitDetailsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetCommitDetailsRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ CommitDetails details = CommitDetails::fromJSON(json.data(), &error);
+
+ emit success(details);
+}
+
+// /api2/user/foo@foo.com/resized/36
+GetAvatarRequest::GetAvatarRequest(const Account& account,
+ const QString& email,
+ qint64 mtime,
+ int size)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(kAvatarUrl + email + "/resized/" +
+ QString::number(size) + "/"),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ fetch_img_req_(NULL),
+ mtime_(mtime)
+{
+ account_ = account;
+ email_ = email;
+}
+
+GetAvatarRequest::~GetAvatarRequest()
+{
+ if (fetch_img_req_) {
+ fetch_img_req_->deleteLater();
+ fetch_img_req_ = nullptr;
+ }
+}
+
+void GetAvatarRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetAvatarRequest: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ const char* avatar_url =
+ json_string_value(json_object_get(json.data(), "url"));
+
+ // we don't need to fetch all images if we have latest one
+ json_t* mtime = json_object_get(json.data(), "mtime");
+ if (!mtime) {
+ qWarning("GetAvatarRequest: no 'mtime' value in response\n");
+ }
+ else {
+ qint64 new_mtime = json_integer_value(mtime);
+ // When mtime_ < 0 it means there is no local cache yet
+ if (mtime_ >= 0 && new_mtime == mtime_) {
+ emit success(QImage());
+ return;
+ }
+ mtime_ = new_mtime;
+ }
+
+ if (!avatar_url) {
+ qWarning("GetAvatarRequest: no 'url' value in response\n");
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QString url = QUrl::fromPercentEncoding(avatar_url);
+
+ fetch_img_req_ = new FetchImageRequest(url);
+
+ connect(fetch_img_req_, SIGNAL(failed(const ApiError&)), this,
+ SIGNAL(failed(const ApiError&)));
+ connect(fetch_img_req_, SIGNAL(success(const QImage&)), this,
+ SIGNAL(success(const QImage&)));
+ fetch_img_req_->send();
+}
+
+FetchImageRequest::FetchImageRequest(const QString& img_url)
+ : SeafileApiRequest(QUrl(img_url), SeafileApiRequest::METHOD_GET)
+{
+}
+
+void FetchImageRequest::requestSuccess(QNetworkReply& reply)
+{
+ QImage img;
+ img.loadFromData(reply.readAll());
+
+ if (img.isNull()) {
+ qWarning("FetchImageRequest: invalid image data\n");
+ emit failed(ApiError::fromHttpError(400));
+ }
+ else {
+ emit success(img);
+ }
+}
+
+SetRepoPasswordRequest::SetRepoPasswordRequest(const Account& account,
+ const QString& repo_id,
+ const QString& password)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(kSetRepoPasswordUrl + repo_id + "/"),
+ SeafileApiRequest::METHOD_POST,
+ account.token)
+{
+ setFormParam("password", password);
+}
+
+void SetRepoPasswordRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+ServerInfoRequest::ServerInfoRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kServerInfoUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ account_(account)
+{
+}
+
+void ServerInfoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+ ServerInfo ret;
+
+ if (dict.contains("version")) {
+ ret.parseVersionFromString(dict["version"].toString());
+ }
+
+ if (dict.contains("encrypted_library_version")) {
+ ret.parseEncryptedLibraryVersionFromString(dict["encrypted_library_version"].toString());
+ }
+
+ if (dict.contains("features")) {
+ ret.parseFeatureFromStrings(dict["features"].toStringList());
+ }
+
+ if (dict.contains("desktop-custom-logo")) {
+ ret.customLogo = dict["desktop-custom-logo"].toString();
+ }
+
+ if (dict.contains("desktop-custom-brand")) {
+ ret.customBrand = dict["desktop-custom-brand"].toString();
+ }
+
+ emit success(account_, ret);
+}
+
+LogoutDeviceRequest::LogoutDeviceRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kLogoutDeviceUrl),
+ SeafileApiRequest::METHOD_POST,
+ account.token),
+ account_(account)
+{
+}
+
+void LogoutDeviceRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+GetRepoTokensRequest::GetRepoTokensRequest(const Account& account,
+ const QStringList& repo_ids,
+ int max_retries,
+ int batch_size)
+ : SeafileApiRequest(account.getAbsoluteUrl(kGetRepoTokensUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ account_(account),
+ repo_ids_(repo_ids),
+ max_retries_(max_retries),
+ batch_offset_(0),
+ batch_size_(batch_size)
+{
+}
+
+void GetRepoTokensRequest::send()
+{
+ doNextBatch();
+}
+
+void GetRepoTokensRequest::doNextBatch()
+{
+ if (batch_offset_ >= repo_ids_.size()) {
+ emit success();
+ return;
+ }
+
+ int count;
+ count = qMin(batch_size_, repo_ids_.size() - batch_offset_);
+ batch_req_.reset(new SingleBatchRepoTokensRequest(
+ account_, repo_ids_.mid(batch_offset_, count)));
+
+ connect(batch_req_.data(),
+ SIGNAL(failed(const ApiError &)),
+ this,
+ SIGNAL(failed(const ApiError &)));
+ connect(batch_req_.data(), SIGNAL(success()), this, SLOT(batchSuccess()));
+ batch_req_->send();
+
+ // printf("sending request for one batch: offset = %d, count = %d\n",
+ // batch_offset_,
+ // count);
+}
+
+void GetRepoTokensRequest::batchSuccess()
+{
+ const QMap<QString, QString>& tokens = batch_req_->repoTokens();
+
+ // printf ("one batch finished, offset = %d, count = %d\n", batch_offset_, tokens.size());
+
+ repo_tokens_.unite(tokens);
+ batch_offset_ += batch_req_->repoIds().size();
+ doNextBatch();
+}
+
+void GetRepoTokensRequest::requestSuccess(QNetworkReply& reply)
+{
+ // Just a place holder. A `GetRepoTokensRequest` is a wrapper around a
+ // series of `SingleBatchRepoTokensRequest`, which really sends the api
+ // requests.
+}
+
+SingleBatchRepoTokensRequest::SingleBatchRepoTokensRequest(const Account& account,
+ const QStringList& repo_ids)
+ : SeafileApiRequest(account.getAbsoluteUrl(kGetRepoTokensUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ repo_ids_(repo_ids)
+{
+ setUrlParam("repos", repo_ids.join(","));
+}
+
+void SingleBatchRepoTokensRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("SingleBatchRepoTokensRequest: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ foreach (const QString& repo_id, dict.keys()) {
+ repo_tokens_[repo_id] = dict[repo_id].toString();
+ }
+
+ emit success();
+}
+
+GetLoginTokenRequest::GetLoginTokenRequest(const Account& account,
+ const QString& next_url)
+ : SeafileApiRequest(account.getAbsoluteUrl(kGetLoginTokenUrl),
+ SeafileApiRequest::METHOD_POST,
+ account.token),
+ account_(account),
+ next_url_(next_url)
+{
+}
+
+void GetLoginTokenRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetLoginTokenRequest: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ if (!dict.contains("token")) {
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+ emit success(dict["token"].toString());
+}
+
+FileSearchRequest::FileSearchRequest(const Account& account,
+ const QString& keyword,
+ int page,
+ int per_page,
+ const QString& repo_id)
+ : SeafileApiRequest(account.getAbsoluteUrl(kFileSearchUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ keyword_(keyword),
+ page_(page)
+{
+ setUrlParam("q", keyword_);
+ if (page > 0) {
+ setUrlParam("page", QString::number(page));
+ }
+ // per_page = 2;
+ setUrlParam("per_page", QString::number(per_page));
+ if (!repo_id.isEmpty()) {
+ setUrlParam("search_repo", repo_id);
+ }
+}
+
+void FileSearchRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("FileSearchResult: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ if (!dict.contains("results")) {
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+ QList<QVariant> results = dict["results"].toList();
+ std::vector<FileSearchResult> retval;
+ Q_FOREACH(const QVariant& result, results)
+ {
+ FileSearchResult tmp;
+ QMap<QString, QVariant> map = result.toMap();
+ if (map.empty())
+ continue;
+ tmp.repo_id = map["repo_id"].toString();
+ tmp.repo_name = RepoService::instance()->getRepo(tmp.repo_id).name;
+ tmp.name = map["name"].toString();
+ tmp.oid = map["oid"].toString();
+ tmp.last_modified = map["last_modified"].toLongLong();
+ tmp.fullpath = map["fullpath"].toString();
+ tmp.size = map["size"].toLongLong();
+ tmp.is_dir = map["is_dir"].toBool();
+ retval.push_back(tmp);
+ }
+ bool has_more = dict["has_more"].toBool();
+ bool is_loading_more = page_ > 1;
+
+ emit success(retval, is_loading_more, has_more);
+}
+
+FetchCustomLogoRequest::FetchCustomLogoRequest(const QUrl& url)
+ : SeafileApiRequest(url, SeafileApiRequest::METHOD_GET)
+{
+ setUseCache(true);
+}
+
+void FetchCustomLogoRequest::requestSuccess(QNetworkReply& reply)
+{
+ QPixmap logo;
+ logo.loadFromData(reply.readAll());
+
+ if (logo.isNull()) {
+ qWarning("FetchCustomLogoRequest: invalid image data\n");
+ emit failed(ApiError::fromHttpError(400));
+ }
+ else {
+ emit success(url());
+ }
+}
+
+FetchAccountInfoRequest::FetchAccountInfoRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kAccountInfoUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+ account_ = account;
+}
+
+void FetchAccountInfoRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("FetchAccountInfoRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+
+ AccountInfo info;
+ info.email = dict["email"].toString();
+ info.name = dict["name"].toString();
+ info.totalStorage = dict["total"].toLongLong();
+ info.usedStorage = dict["usage"].toLongLong();
+ if (info.name.isEmpty()) {
+ info.name = dict["nickname"].toString();
+ }
+ emit success(info);
+}
+
+PrivateShareRequest::PrivateShareRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const SeafileUser& user,
+ int group_id,
+ SharePermission permission,
+ ShareType share_type,
+ ShareOperation op)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
+ op == UPDATE_SHARE ? METHOD_POST : (op == REMOVE_SHARE ? METHOD_DELETE
+ : METHOD_PUT),
+ account.token),
+ group_id_(share_type == SHARE_TO_GROUP ? group_id : -1),
+ user_(share_type == SHARE_TO_USER ? user: SeafileUser()),
+ permission_(permission),
+ share_type_(share_type),
+ share_operation_(op)
+{
+ setUrlParam("p", path);
+ setFormParam("permission", permission == READ_ONLY ? "r" : "rw");
+ bool is_add = op == ADD_SHARE;
+ if (is_add) {
+ setFormParam("share_type",
+ share_type == SHARE_TO_USER ? "user" : "group");
+ }
+ else {
+ setUrlParam("share_type",
+ share_type == SHARE_TO_USER ? "user" : "group");
+ }
+
+ if (share_type == SHARE_TO_USER) {
+ if (is_add) {
+ setFormParam("username", user_.email);
+ }
+ else {
+ setUrlParam("username", user_.email);
+ }
+ }
+ else {
+ if (is_add) {
+ setFormParam("group_id", QString::number(group_id));
+ }
+ else {
+ setUrlParam("group_id", QString::number(group_id));
+ }
+ }
+}
+
+void PrivateShareRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("PrivateShareRequest: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ emit success();
+}
+
+
+FetchGroupsAndContactsRequest::FetchGroupsAndContactsRequest(
+ const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kFetchGroupsAndContactsUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+}
+
+void FetchGroupsAndContactsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("FetchGroupsAndContactsRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QList<SeafileGroup> groups;
+ QList<SeafileUser> contacts;
+
+ json_t* groups_array = json_object_get(json.data(), "groups");
+ if (groups_array) {
+ int i, n = json_array_size(groups_array);
+ for (i = 0; i < n; i++) {
+ json_t* group_object = json_array_get(groups_array, i);
+ const char* name =
+ json_string_value(json_object_get(group_object, "name"));
+ int group_id =
+ json_integer_value(json_object_get(group_object, "id"));
+ if (name && group_id) {
+ SeafileGroup group;
+ group.id = group_id;
+ group.name = QString::fromUtf8(name);
+ const char* owner =
+ json_string_value(json_object_get(group_object, "creator"));
+ if (owner) {
+ group.owner = QString::fromUtf8(owner);
+ }
+ groups.push_back(group);
+ }
+ }
+ }
+
+ json_t* contacts_array = json_object_get(json.data(), "contacts");
+ if (contacts_array) {
+ int i, n = json_array_size(contacts_array);
+
+ for (i = 0; i < n; i++) {
+ json_t* contact_object = json_array_get(contacts_array, i);
+ const char* email =
+ json_string_value(json_object_get(contact_object, "email"));
+ if (email) {
+ SeafileUser contact;
+ contact.email = QString::fromUtf8(email);
+ contact.name = QString::fromUtf8(
+ json_string_value(json_object_get(contact_object, "name")));
+ contacts.push_back(contact);
+ }
+ }
+ }
+
+ emit success(groups, contacts);
+}
+
+GetPrivateShareItemsRequest::GetPrivateShareItemsRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kDirSharedItemsUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+ setUrlParam("p", path);
+}
+
+void GetPrivateShareItemsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetPrivateShareItemsRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QList<GroupShareInfo> group_shares;
+ QList<UserShareInfo> user_shares;
+
+ int i, n = json_array_size(json.data());
+ for (i = 0; i < n; i++) {
+ json_t* share_info_object = json_array_get(json.data(), i);
+ Json share_info(share_info_object);
+ QString share_type = share_info.getString("share_type");
+ QString permission = share_info.getString("permission");
+ if (share_type == "group") {
+ // group share
+ Json group = share_info.getObject("group_info");
+ GroupShareInfo group_share;
+ group_share.group.id = group.getLong("id");
+ group_share.group.name = group.getString("name");
+ group_share.permission = ::permissionfromString(permission);
+ group_shares.push_back(group_share);
+ }
+ else if (share_type == "user") {
+ Json user = share_info.getObject("user_info");
+ UserShareInfo user_share;
+ user_share.user.email = user.getString("name");
+ user_share.user.name = user.getString("nickname");
+ user_share.permission = ::permissionfromString(permission);
+ user_shares.push_back(user_share);
+ }
+ }
+
+ emit success(group_shares, user_shares);
+}
+
+RemoteWipeReportRequest::RemoteWipeReportRequest(const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kRemoteWipeReportUrl),
+ SeafileApiRequest::METHOD_POST)
+{
+ setFormParam(QString("token"), account.token);
+}
+
+void RemoteWipeReportRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+SearchUsersRequest::SearchUsersRequest(
+ const Account& account, const QString& pattern)
+ : SeafileApiRequest(account.getAbsoluteUrl(kSearchUsersUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ pattern_(pattern)
+{
+ setUrlParam("q", pattern);
+}
+
+void SearchUsersRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("SearchUsersRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QList<SeafileUser> users;
+
+ json_t* users_array = json_object_get(json.data(), "users");
+ if (users_array) {
+ int i, n = json_array_size(users_array);
+
+ for (i = 0; i < n; i++) {
+ json_t* user_object = json_array_get(users_array, i);
+ const char* email =
+ json_string_value(json_object_get(user_object, "email"));
+ if (email) {
+ SeafileUser user;
+ user.email = QString::fromUtf8(email);
+ user.name = QString::fromUtf8(
+ json_string_value(json_object_get(user_object, "name")));
+ user.contact_email = QString::fromUtf8(
+ json_string_value(json_object_get(user_object, "contact_email")));
+ user.avatar_url = QString::fromUtf8(
+ json_string_value(json_object_get(user_object, "avatar_url")));
+ users.push_back(user);
+ }
+ }
+ }
+
+ emit success(users);
+}
+
+
+FetchGroupsRequest::FetchGroupsRequest(
+ const Account& account)
+ : SeafileApiRequest(account.getAbsoluteUrl(kFetchGroupsUrl),
+ SeafileApiRequest::METHOD_GET,
+ account.token)
+{
+ setUrlParam("with_msg", "false");
+}
+
+void FetchGroupsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("FetchGroupsRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QList<SeafileGroup> groups;
+
+ int i, n = json_array_size(json.data());
+ for (i = 0; i < n; i++) {
+ json_t* group_object = json_array_get(json.data(), i);
+ const char* name =
+ json_string_value(json_object_get(group_object, "name"));
+ int group_id =
+ json_integer_value(json_object_get(group_object, "id"));
+ if (name && group_id) {
+ SeafileGroup group;
+ group.id = group_id;
+ group.name = QString::fromUtf8(name);
+ const char* owner =
+ json_string_value(json_object_get(group_object, "creator"));
+ if (owner) {
+ group.owner = QString::fromUtf8(owner);
+ }
+ groups.push_back(group);
+ }
+ }
+
+ emit success(groups);
+}
+
+GetThumbnailRequest::GetThumbnailRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetThumbnailUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ account_(account),
+ repo_id_(repo_id),
+ path_(path),
+ dirent_id_(dirent_id),
+ size_(size)
+{
+ setUrlParam("p", path);
+ setUrlParam("size", QString::number(size));
+ setUseCache(true);
+}
+
+void GetThumbnailRequest::requestSuccess(QNetworkReply& reply)
+{
+ QPixmap pixmap;
+ pixmap.loadFromData(reply.readAll());
+
+ if (pixmap.isNull()) {
+ qWarning("GetThumbnailRequest: invalid image data\n");
+ emit failed(ApiError::fromHttpError(400));
+ }
+ else {
+ emit success(pixmap);
+ }
+}
+
+UnshareRepoRequest::UnshareRepoRequest(const Account& account,
+ const QString& repo_id,
+ const QString& from_user)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kRepoSharedUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_DELETE,
+ account.token),
+ repo_id_(repo_id)
+{
+ setUrlParam("share_type", "personal");
+ setUrlParam("from", from_user);
+}
+
+void UnshareRepoRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+CreateFileUploadLinkRequest::CreateFileUploadLinkRequest(const Account& account,
+ const QString &repo_id,
+ const QString &path,
+ const QString &password)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kCreateFileUploadLink)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ repo_id_(repo_id),
+ path_(path),
+ password_(password)
+{
+ setFormParam(QString("repo_id"), repo_id);
+ setFormParam(QString("path"), path);
+ if (!password.isNull()) {
+ setFormParam(QString("password"), password);
+ }
+}
+
+void CreateFileUploadLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ UploadLinkInfo link_info;
+ link_info.username = dict["username"].toString();
+ link_info.repo_id = dict["repo_id"].toString();
+ link_info.ctime = dict["ctime"].toString();
+ link_info.token = dict["token"].toString();
+ link_info.link = dict["link"].toString();
+ link_info.path = dict["path"].toString();
+
+ emit success(link_info);
+}
+
+GetUploadFileLinkRequest::GetUploadFileLinkRequest(const QString& link)
+ : SeafileApiRequest(link, SeafileApiRequest::METHOD_GET)
+{
+}
+
+void GetUploadFileLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ QString reply_content(dict["upload_link"].toString());
+
+ do {
+ if (reply_content.size() <= 2)
+ break;
+ QUrl new_url(reply_content);
+ if (!new_url.isValid())
+ break;
+
+ emit success(reply_content);
+ return;
+ } while (0);
+ emit failed(ApiError::fromHttpError(500));
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_API_REQUESTS_H
+#define SEAFILE_CLIENT_API_REQUESTS_H
+
+#include <QMap>
+#include <QScopedPointer>
+#include <vector>
+
+#include "account.h"
+#include "api-request.h"
+#include "contact-share-info.h"
+#include "server-repo.h"
+#include "server-repo.h"
+
+class QNetworkReply;
+class QImage;
+class QStringList;
+
+class ServerRepo;
+class Account;
+class StarredItem;
+class SeafEvent;
+class CommitDetails;
+
+class PingServerRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ PingServerRequest(const QUrl& serverAddr);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success();
+
+private:
+ Q_DISABLE_COPY(PingServerRequest)
+};
+
+class LoginRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+
+public:
+ LoginRequest(const QUrl& serverAddr,
+ const QString& username,
+ const QString& password,
+ const QString& computer_name);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success(const QString& token, const QString& s2fa_token);
+
+private:
+ Q_DISABLE_COPY(LoginRequest)
+};
+
+
+class ListReposRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+
+public:
+ explicit ListReposRequest(const Account& account);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success(const std::vector<ServerRepo>& repos);
+
+private:
+ Q_DISABLE_COPY(ListReposRequest)
+};
+
+
+class RepoDownloadInfo
+{
+public:
+ int repo_version;
+ QString email;
+ QString token;
+ QString repo_id;
+ QString repo_name;
+ bool encrypted;
+ bool readonly;
+ int enc_version;
+ QString magic;
+ QString random_key;
+ QString more_info;
+
+ static RepoDownloadInfo fromDict(QMap<QString, QVariant>& dict,
+ const QUrl& url,
+ bool read_only);
+};
+
+class DownloadRepoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+
+public:
+ explicit DownloadRepoRequest(const Account& account,
+ const QString& repo_id,
+ bool read_only);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success(const RepoDownloadInfo& info);
+
+private:
+ Q_DISABLE_COPY(DownloadRepoRequest)
+
+ bool read_only_;
+};
+
+class GetRepoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+
+public:
+ explicit GetRepoRequest(const Account& account, const QString& repoid);
+ const QString& repoid()
+ {
+ return repoid_;
+ }
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success(const ServerRepo& repo);
+
+private:
+ Q_DISABLE_COPY(GetRepoRequest)
+ const QString repoid_;
+};
+
+class CreateRepoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+
+public:
+ CreateRepoRequest(const Account& account,
+ const QString& name,
+ const QString& desc,
+ const QString& passwd);
+ CreateRepoRequest(const Account& account,
+ const QString& name,
+ const QString& desc,
+ int enc_version,
+ const QString& repo_id,
+ const QString& magic,
+ const QString& random_key);
+ // Constructor for seafile encryption v3
+ CreateRepoRequest(const Account& account,
+ const QString& name,
+ const QString& desc,
+ int enc_version,
+ const QString& repo_id,
+ const QString& magic,
+ const QString& random_key,
+ const QString& salt);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success(const RepoDownloadInfo& info);
+
+private:
+ Q_DISABLE_COPY(CreateRepoRequest)
+};
+
+class CreateSubrepoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+
+public:
+ explicit CreateSubrepoRequest(const Account& account,
+ const QString& name,
+ const QString& repoid,
+ const QString& path,
+ const QString& passwd);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success(const QString& sub_repoid);
+
+private:
+ Q_DISABLE_COPY(CreateSubrepoRequest)
+};
+
+class GetUnseenSeahubNotificationsRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+
+public:
+ explicit GetUnseenSeahubNotificationsRequest(const Account& account);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+signals:
+ void success(int count);
+
+private:
+ Q_DISABLE_COPY(GetUnseenSeahubNotificationsRequest)
+};
+
+class GetDefaultRepoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetDefaultRepoRequest(const Account& account);
+
+signals:
+ void success(bool exists, const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetDefaultRepoRequest);
+};
+
+class CreateDefaultRepoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ CreateDefaultRepoRequest(const Account& account);
+
+signals:
+ void success(const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(CreateDefaultRepoRequest);
+};
+
+class GetStarredFilesRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetStarredFilesRequest(const Account& account);
+
+signals:
+ void success(const std::vector<StarredItem>& starred_files);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetStarredFilesRequest);
+};
+
+// get starred item api v2.1
+class GetStarredFilesRequestV2 : public SeafileApiRequest
+{
+Q_OBJECT
+public:
+ GetStarredFilesRequestV2(const Account& account);
+
+signals:
+ void success(const std::vector<StarredItem>& starred_files);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetStarredFilesRequestV2);
+};
+
+class GetEventsRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetEventsRequest(const Account& account, int start = 0);
+
+signals:
+ void success(const std::vector<SeafEvent>& events, int more_offset);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetEventsRequest);
+};
+
+class GetEventsRequestV2 : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetEventsRequestV2(const Account& account, int page = 1, int perpage = 25, int avatar_size = 36);
+
+signals:
+ void success(const std::vector<SeafEvent>& events);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetEventsRequestV2);
+};
+
+class GetCommitDetailsRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetCommitDetailsRequest(const Account& account,
+ const QString& repo_id,
+ const QString& commit_id);
+
+signals:
+ void success(const CommitDetails& result);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetCommitDetailsRequest);
+};
+
+class FetchImageRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ FetchImageRequest(const QString& img_url);
+
+signals:
+ void success(const QImage& avatar);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(FetchImageRequest);
+};
+
+class GetAvatarRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetAvatarRequest(const Account& account,
+ const QString& email,
+ qint64 mtime,
+ int size);
+
+ ~GetAvatarRequest();
+
+ const QString& email() const
+ {
+ return email_;
+ }
+ const Account& account() const
+ {
+ return account_;
+ }
+ qint64 mtime() const
+ {
+ return mtime_;
+ }
+
+signals:
+ void success(const QImage& avatar);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetAvatarRequest);
+
+ FetchImageRequest* fetch_img_req_;
+
+ QString email_;
+
+ Account account_;
+
+ qint64 mtime_;
+};
+
+class SetRepoPasswordRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ SetRepoPasswordRequest(const Account& account,
+ const QString& repo_id,
+ const QString& password);
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(SetRepoPasswordRequest);
+};
+
+class ServerInfoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ ServerInfoRequest(const Account& account);
+
+signals:
+ void success(const Account& account, const ServerInfo& info);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(ServerInfoRequest);
+ const Account account_;
+};
+
+class LogoutDeviceRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ LogoutDeviceRequest(const Account& account);
+
+ const Account& account()
+ {
+ return account_;
+ }
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(LogoutDeviceRequest);
+
+ Account account_;
+};
+
+class SingleBatchRepoTokensRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ SingleBatchRepoTokensRequest(const Account& account, const QStringList& repo_ids);
+
+ const QMap<QString, QString>& repoTokens() const
+ {
+ return repo_tokens_;
+ }
+
+ const QStringList repoIds() const {
+ return repo_ids_;
+ }
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(SingleBatchRepoTokensRequest);
+
+ QStringList repo_ids_;
+ QMap<QString, QString> repo_tokens_;
+};
+
+// Request repo sync tokens from the server, and break the request into batches
+// if there are too many, to avoid request URI too large.
+class GetRepoTokensRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetRepoTokensRequest(const Account& account, const QStringList& repo_ids, int max_retry, int batch_size=50);
+
+ virtual void send() Q_DECL_OVERRIDE;
+
+ const QMap<QString, QString>& repoTokens() const
+ {
+ return repo_tokens_;
+ }
+
+ int maxRetries() const { return max_retries_; }
+ const QStringList& repoIds() const { return repo_ids_; }
+ const Account& account() const
+ {
+ return account_;
+ }
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private slots:
+ void batchSuccess();
+
+private:
+ Q_DISABLE_COPY(GetRepoTokensRequest);
+
+ void doNextBatch();
+
+ Account account_;
+ QStringList repo_ids_;
+ QMap<QString, QString> repo_tokens_;
+ int max_retries_;
+
+ // The start position of the next batch
+ int batch_offset_;
+ // How many tokens to ask in a single request
+ int batch_size_;
+
+ QScopedPointer<SingleBatchRepoTokensRequest, QScopedPointerDeleteLater> batch_req_;
+};
+
+class GetLoginTokenRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetLoginTokenRequest(const Account& account, const QString& next_url);
+
+ const Account& account()
+ {
+ return account_;
+ }
+ const QString& nextUrl()
+ {
+ return next_url_;
+ }
+
+signals:
+ void success(const QString& token);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetLoginTokenRequest);
+
+ Account account_;
+ QString next_url_;
+};
+
+struct FileSearchResult {
+ QString repo_id;
+ QString repo_name;
+ QString name;
+ QString oid;
+ qint64 last_modified;
+ QString fullpath;
+ qint64 size;
+ bool is_dir;
+};
+
+Q_DECLARE_METATYPE(FileSearchResult)
+
+class FileSearchRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ FileSearchRequest(const Account& account,
+ const QString& keyword,
+ int page = 0,
+ int per_page = 10,
+ const QString& repo_id = QString());
+ const QString& keyword() const
+ {
+ return keyword_;
+ }
+
+signals:
+ void success(const std::vector<FileSearchResult>& result,
+ bool is_loading_more,
+ bool has_more);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(FileSearchRequest);
+
+ const QString keyword_;
+ const int page_;
+};
+
+class FetchCustomLogoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ FetchCustomLogoRequest(const QUrl& url);
+
+signals:
+ void success(const QUrl& url);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(FetchCustomLogoRequest);
+};
+
+class FetchAccountInfoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ FetchAccountInfoRequest(const Account& account);
+
+ const Account& account() const
+ {
+ return account_;
+ }
+
+signals:
+ void success(const AccountInfo& info);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(FetchAccountInfoRequest);
+
+ Account account_;
+};
+
+class PrivateShareRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ enum ShareOperation {
+ ADD_SHARE,
+ UPDATE_SHARE,
+ REMOVE_SHARE,
+ };
+ PrivateShareRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const SeafileUser& user,
+ int group_id,
+ SharePermission permission,
+ ShareType share_type,
+ ShareOperation op);
+
+ ShareOperation shareOperation() const
+ {
+ return share_operation_;
+ }
+
+ int groupId() const
+ {
+ return share_type_ == SHARE_TO_GROUP ? group_id_ : -1;
+ };
+
+ SeafileUser user() const
+ {
+ return share_type_ == SHARE_TO_USER ? user_ : SeafileUser();
+ };
+
+ SharePermission permission() const
+ {
+ return permission_;
+ }
+
+ ShareType shareType() const
+ {
+ return share_type_;
+ }
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(PrivateShareRequest);
+
+ int group_id_;
+ SeafileUser user_;
+ SharePermission permission_;
+ ShareType share_type_;
+ ShareOperation share_operation_;
+};
+
+class GetPrivateShareItemsRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetPrivateShareItemsRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path);
+
+signals:
+ void success(const QList<GroupShareInfo>&, const QList<UserShareInfo>&);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetPrivateShareItemsRequest);
+};
+
+class FetchGroupsAndContactsRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ FetchGroupsAndContactsRequest(const Account& account);
+
+signals:
+ void success(const QList<SeafileGroup>&, const QList<SeafileUser>&);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(FetchGroupsAndContactsRequest);
+};
+
+
+class RemoteWipeReportRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ RemoteWipeReportRequest(const Account& account);
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(RemoteWipeReportRequest);
+};
+
+class SearchUsersRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ SearchUsersRequest(const Account& account, const QString& pattern);
+
+ QString pattern() const { return pattern_; }
+
+signals:
+ void success(const QList<SeafileUser>& users);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(SearchUsersRequest);
+
+ QString pattern_;
+};
+
+class FetchGroupsRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ FetchGroupsRequest(const Account& account);
+
+signals:
+ void success(const QList<SeafileGroup>&);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(FetchGroupsRequest);
+};
+
+class GetThumbnailRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetThumbnailRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size);
+
+ const Account& account() const
+ {
+ return account_;
+ }
+ const QString& repoId() const
+ {
+ return repo_id_;
+ }
+ const QString& path() const
+ {
+ return path_;
+ }
+ const QString& direntId() const
+ {
+ return dirent_id_;
+ }
+ uint size() const
+ {
+ return size_;
+ }
+signals:
+ void success(const QPixmap& thumbnail);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetThumbnailRequest);
+ Account account_;
+ QString repo_id_;
+ QString path_;
+ QString dirent_id_;
+ uint size_;
+};
+
+class UnshareRepoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ UnshareRepoRequest(const Account& account,
+ const QString& repo_id,
+ const QString& from_user);
+
+ const QString& repoId() { return repo_id_; }
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(UnshareRepoRequest);
+
+ QString repo_id_;
+};
+
+struct UploadLinkInfo {
+ QString username;
+ QString repo_id;
+ QString ctime;
+ QString token;
+ QString link;
+ QString path;
+};
+
+class CreateFileUploadLinkRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ CreateFileUploadLinkRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& password = QString());
+
+signals:
+ void success(const UploadLinkInfo& link_info);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(CreateFileUploadLinkRequest);
+ QString repo_id_;
+ QString path_;
+ QString password_;
+};
+
+class GetUploadFileLinkRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetUploadFileLinkRequest(const QString& link);
+
+signals:
+ void success(const QString& url);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetUploadFileLinkRequest);
+};
+
+#endif // SEAFILE_CLIENT_API_REQUESTS_H
--- /dev/null
+#ifndef SEAFILE_CLIENT_API_SERVER_INFO_H
+#define SEAFILE_CLIENT_API_SERVER_INFO_H
+#include <QString>
+#include <QStringList>
+
+class ServerInfo {
+public:
+ unsigned majorVersion;
+ unsigned minorVersion;
+ unsigned patchVersion;
+ unsigned encryptedLibraryVersion = 2;
+ bool proEdition;
+ bool officePreview;
+ bool fileSearch;
+ bool disableSyncWithAnyFolder;
+ QString customBrand;
+ QString customLogo;
+
+ bool operator== (const ServerInfo &rhs) const {
+ return majorVersion == rhs.majorVersion &&
+ minorVersion == rhs.minorVersion &&
+ patchVersion == rhs.patchVersion &&
+ encryptedLibraryVersion == rhs.encryptedLibraryVersion &&
+ proEdition == rhs.proEdition &&
+ officePreview == rhs.officePreview &&
+ fileSearch == rhs.fileSearch &&
+ disableSyncWithAnyFolder == rhs.disableSyncWithAnyFolder &&
+ customBrand == rhs.customBrand &&
+ customLogo == rhs.customLogo;
+ }
+ bool operator!= (const ServerInfo &rhs) const {
+ return !(*this == rhs);
+ }
+ bool parseVersionFromString(const QString &version) {
+ QStringList versions = version.split('.');
+ if (versions.size() < 3)
+ return false;
+ majorVersion = versions[0].toInt();
+ minorVersion = versions[1].toInt();
+ patchVersion = versions[2].toInt();
+ return true;
+ }
+
+ bool parseEncryptedLibraryVersionFromString(const QString &version) {
+ bool ok;
+ encryptedLibraryVersion = version.toInt(&ok);
+ return ok;
+ }
+
+ void parseFeatureFromStrings(const QStringList& input) {
+ proEdition = false;
+ officePreview = false;
+ fileSearch = false;
+ disableSyncWithAnyFolder = false;
+ Q_FOREACH(const QString& key, input)
+ {
+ parseFeatureFromString(key);
+ }
+ }
+ bool parseFeatureFromString(const QString& key, bool value = true) {
+ if (key == "seafile-pro") {
+ proEdition = value;
+ } else if (key == "office-preview") {
+ officePreview = value;
+ } else if (key == "file-search") {
+ fileSearch = value;
+ } else if (key == "disable-sync-with-any-folder") {
+ disableSyncWithAnyFolder = value;
+ } else {
+ return false;
+ }
+ return true;
+ }
+ QString getVersionString() const {
+ return QString("%1.%2.%3")
+ .arg(QString::number(majorVersion))
+ .arg(QString::number(minorVersion))
+ .arg(QString::number(patchVersion));
+ }
+
+ int getEncryptedLibraryVersion() const {
+ return encryptedLibraryVersion;
+ }
+
+ QStringList getFeatureStrings() const {
+ QStringList result;
+ if (proEdition)
+ result.push_back("seafile-pro");
+ if (officePreview)
+ result.push_back("office-preview");
+ if (fileSearch)
+ result.push_back("file-search");
+ if (disableSyncWithAnyFolder)
+ result.push_back("disable-sync-with-any-folder");
+ return result;
+ }
+};
+
+
+
+#endif // SEAFILE_CLIENT_API_SERVER_INFO_H
--- /dev/null
+#include <vector>
+#include <jansson.h>
+#include <QPixmap>
+
+#include "server-repo.h"
+
+namespace {
+
+QString getStringFromJson(const json_t *json, const char* key)
+{
+ return QString::fromUtf8(json_string_value(json_object_get(json, key)));
+}
+
+} // namespace
+
+
+ServerRepo ServerRepo::fromJSON(const json_t *json, json_error_t */* error */)
+{
+ ServerRepo repo;
+ repo.id = getStringFromJson(json, "id");
+ repo.name = getStringFromJson(json, "name");
+ repo.description = getStringFromJson(json, "desc");
+
+ repo.mtime = json_integer_value(json_object_get(json, "mtime"));
+ repo.size = json_integer_value(json_object_get(json, "size"));
+ repo.root = getStringFromJson(json, "root");
+
+ repo.encrypted = json_is_true(json_object_get(json, "encrypted"));
+
+ repo.type = getStringFromJson(json, "type");
+ repo.permission = getStringFromJson(json, "permission");
+ repo.readonly = (repo.permission == "r") ? true : false;
+
+ repo._virtual = json_is_true(json_object_get(json, "virtual"));
+
+ if (repo.type == "grepo") {
+ repo.owner = getStringFromJson(json, "share_from");
+ repo.group_name = getStringFromJson(json, "owner");
+ repo.group_id = json_integer_value(json_object_get(json, "groupid"));
+ } else {
+ repo.owner = getStringFromJson(json, "owner");
+ repo.group_name = QString();
+ repo.group_id = 0;
+ }
+
+ return repo;
+}
+
+std::vector<ServerRepo> ServerRepo::listFromJSON(const json_t *json, json_error_t *error)
+{
+ std::vector<ServerRepo> repos;
+ for (size_t i = 0; i < json_array_size(json); i++) {
+ ServerRepo repo = fromJSON(json_array_get(json, i), error);
+ repos.push_back(repo);
+ }
+
+ return repos;
+}
+
+QIcon ServerRepo::getIcon() const
+{
+ if (this->isSubfolder()) {
+ return QIcon(":/images/main-panel/folder.png");
+ } else if (encrypted) {
+ return QIcon(":/images/main-panel/library-encrypted.png");
+ } else if (readonly) {
+ return QIcon(":/images/main-panel/library-readonly.png");
+ } else {
+ return QIcon(":/images/main-panel/library-normal.png");
+ }
+}
+
+QPixmap ServerRepo::getPixmap(int size) const
+{
+ return getIcon().pixmap(size);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SERVER_REPO_H
+#define SEAFILE_CLIENT_SERVER_REPO_H
+
+#include <vector>
+#include <QString>
+#include <QMetaType>
+#include <QIcon>
+#include <QPixmap>
+#include <jansson.h>
+
+/**
+ * Repo information from seahub api
+ */
+class ServerRepo {
+public:
+ ServerRepo() : encrypted(false), readonly(false), _virtual(false), group_id (0) {};
+
+ QString id;
+ QString name;
+ QString description;
+
+ qint64 mtime;
+ qint64 size;
+ QString root;
+
+ bool encrypted;
+ bool readonly;
+
+ // "virtual" is a reserved word in C++
+ bool _virtual;
+
+ // subfolder attributes
+ QString parent_repo_id;
+ QString parent_path;
+
+ QString type;
+ QString owner;
+ QString permission;
+ QString group_name;
+ int group_id;
+
+ bool isValid() const { return !id.isEmpty(); }
+
+ bool isPersonalRepo() const { return type == "repo"; }
+ bool isSharedRepo() const { return type == "srepo"; }
+ bool isGroupRepo() const { return type == "grepo"; }
+ bool isOrgRepo() const { return isGroupRepo() and group_id == 0; }
+
+ bool isVirtual() const { return _virtual; }
+ bool isSubfolder() const { return !parent_repo_id.isEmpty() && !parent_path.isEmpty(); }
+
+ QIcon getIcon() const;
+ QPixmap getPixmap(int size = 24) const;
+
+ static ServerRepo fromJSON(const json_t*, json_error_t *error);
+ static std::vector<ServerRepo> listFromJSON(const json_t*, json_error_t *json);
+};
+
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(ServerRepo)
+
+
+#endif // SEAFILE_CLIENT_SERVER_REPO_H
--- /dev/null
+#include <jansson.h>
+
+#include <vector>
+#include <QFileInfo>
+#include <QDateTime>
+
+#include "starred-file.h"
+
+namespace {
+
+QString getStringFromJson(const json_t *json, const char* key)
+{
+ return QString::fromUtf8(json_string_value(json_object_get(json, key)));
+}
+
+bool getBoolFromJson(const json_t *json, const char* key)
+{
+ return json_is_true(json_object_get(json, key));
+}
+
+} // namespace
+
+
+StarredItem StarredItem::fromJSON(const json_t *json, json_error_t */* error */)
+{
+ StarredItem file;
+ file.repo_id = getStringFromJson(json, "repo_id");
+ if (file.repo_id.isEmpty()) {
+ file.repo_id = getStringFromJson(json, "repo");
+ }
+ file.repo_name = getStringFromJson(json, "repo_name");
+ file.path = getStringFromJson(json, "path");
+
+ file.mtime = json_integer_value(json_object_get(json, "mtime"));
+ file.size = json_integer_value(json_object_get(json, "size"));
+
+ return file;
+}
+
+StarredItem StarredItem::fromJSONV2(const json_t *json, json_error_t */* error */)
+{
+ StarredItem file;
+ file.repo_id = getStringFromJson(json, "repo_id");
+
+ file.repo_name = getStringFromJson(json, "repo_name");
+ file.path = getStringFromJson(json, "path");
+ bool is_dir = getBoolFromJson(json, "is_dir");
+ file.type = StarredItem::FILE;
+ if (is_dir) {
+ if (file.path == "/") {
+ file.type = StarredItem::REPO;
+ } else {
+ file.type = StarredItem::DIR;
+ }
+ }
+
+ file.obj_name = getStringFromJson(json, "obj_name");
+
+ QString date_time = getStringFromJson(json, "mtime");
+ file.mtime = QDateTime::fromString(date_time, Qt::ISODate).toMSecsSinceEpoch() / 1000;
+
+ file.from_new_api = true;
+
+ return file;
+}
+
+std::vector<StarredItem> StarredItem::listFromJSON(const json_t *json, json_error_t *error, bool is_use_new_json_parser)
+{
+ std::vector<StarredItem> files;
+ for (size_t i = 0; i < json_array_size(json); i++) {
+ StarredItem file;
+ if (is_use_new_json_parser) {
+ file = fromJSONV2(json_array_get(json, i), error);
+ } else {
+ file = fromJSON(json_array_get(json, i), error);
+ }
+ files.push_back(file);
+ }
+
+ return files;
+}
+
+const QString StarredItem::name() const
+{
+ if (from_new_api) {
+ return obj_name;
+ } else {
+ return QFileInfo(path).fileName();
+ }
+}
+
+bool StarredItem::isFile() const
+{
+ return type == FILE;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_STARRED_FILE_H
+#define SEAFILE_CLIENT_STARRED_FILE_H
+
+#include <vector>
+#include <QString>
+#include <QMetaType>
+#include <jansson.h>
+
+class StarredItem {
+public:
+ QString repo_id;
+ QString repo_name;
+ QString path;
+ qint64 size;
+ qint64 mtime;
+ QString obj_name;
+
+ enum StarredItemType {
+ FILE = 0,
+ DIR,
+ REPO
+ } type;
+
+ bool from_new_api;
+
+ static StarredItem fromJSON(const json_t*, json_error_t *error);
+ static StarredItem fromJSONV2(const json_t*, json_error_t *error);
+ static std::vector<StarredItem> listFromJSON(const json_t*, json_error_t *json, bool is_use_new_json_parser = false);
+
+ const QString name() const;
+ bool isFile() const;
+};
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(StarredItem)
+
+#endif // SEAFILE_CLIENT_STARRED_FILE_H
--- /dev/null
+#include "application.h"
+
+#include <objc/objc.h>
+#include <objc/message.h>
+
+#include <QFileOpenEvent>
+
+#include "open-local-helper.h"
+#include "ui/main-window.h"
+#include "seafile-applet.h"
+
+// static bool dockClickHandler(id self,SEL _cmd,...)
+// {
+// Q_UNUSED(self)
+// Q_UNUSED(_cmd)
+// if (seafApplet) {
+// MainWindow *main_win = seafApplet->mainWindow();
+// if (main_win)
+// main_win->showWindow();
+// }
+// return true;
+// }
+
+Application::Application (int &argc, char **argv):QApplication(argc, argv)
+{
+ // objc_object* cls = (objc_object *)objc_getClass("NSApplication");
+ // SEL sharedApplication = sel_registerName("sharedApplication");
+ // objc_object* appInst = objc_msgSend(cls,sharedApplication);
+
+ // if(appInst != NULL)
+ // {
+ // objc_object* delegate = objc_msgSend(appInst, sel_registerName("delegate"));
+ // objc_object* delClass = objc_msgSend(delegate, sel_registerName("class"));
+ // class_addMethod((Class)delClass, sel_registerName("applicationShouldHandleReopen:hasVisibleWindows:"), (IMP)dockClickHandler, "B@:");
+ // }
+}
+
+bool Application::event(QEvent *e)
+{
+ if (e->type() == QEvent::FileOpen)
+ {
+ QFileOpenEvent *event = static_cast<QFileOpenEvent *>(e);
+ // this event has native mac handler callee
+ if(event && event->url().scheme() == "seafile")
+ {
+ qWarning("[FileOpen] trying to open %s\n", event->url().toEncoded().data());
+ if (!seafApplet->started())
+ OpenLocalHelper::instance()->setUrl(event->url().toEncoded().data());
+ else
+ OpenLocalHelper::instance()->openLocalFile(event->url());
+ return true;
+ }
+ }
+ return QApplication::event(e);
+}
--- /dev/null
+/**
+ * Show thr main window when the dock icon is clicked
+ */
+#include <QApplication>
+
+#include "ui/main-window.h"
+class Application : public QApplication {
+ Q_OBJECT
+
+public:
+
+ Application (int& argc, char **argv);
+ bool event(QEvent * e);
+ virtual ~Application() {};
+};
--- /dev/null
+#include <QDesktopServices>
+#include <QHash>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "utils/utils.h"
+
+#include "auto-login-service.h"
+
+namespace {
+
+} // namespace
+
+SINGLETON_IMPL(AutoLoginService)
+
+AutoLoginService::AutoLoginService(QObject *parent)
+ : QObject(parent)
+{
+}
+
+void AutoLoginService::startAutoLogin(const QString& next_url)
+{
+ const Account account = seafApplet->accountManager()->currentAccount();
+ QUrl absolute_url = QUrl(next_url).isRelative()
+ ? account.getAbsoluteUrl(next_url)
+ : next_url;
+ if (!account.isValid() || !account.isAtLeastVersion(4, 2, 0)) {
+ QDesktopServices::openUrl(absolute_url);
+ return;
+ }
+
+ absolute_url.setScheme("");
+ absolute_url.setHost("");
+ QString next = absolute_url.toString().mid(2);
+ GetLoginTokenRequest *req = new GetLoginTokenRequest(account, next);
+
+ connect(req, SIGNAL(success(const QString&)),
+ this, SLOT(onGetLoginTokenSuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetLoginTokenFailed(const ApiError&)));
+
+ req->send();
+}
+
+void AutoLoginService::onGetLoginTokenSuccess(const QString& token)
+{
+ GetLoginTokenRequest *req = (GetLoginTokenRequest *)(sender());
+ // printf("login token is %s\n", token.toUtf8().data());
+
+ QUrl url = req->account().getAbsoluteUrl("/client-login/");
+ QString next_url = req->nextUrl();
+
+ QHash<QString, QString> params;
+ params.insert("token", token);
+ params.insert("next", req->nextUrl());
+ url = includeQueryParams(url, params);
+
+ QDesktopServices::openUrl(url);
+ req->deleteLater();
+}
+
+void AutoLoginService::onGetLoginTokenFailed(const ApiError& error)
+{
+ GetLoginTokenRequest *req = (GetLoginTokenRequest *)(sender());
+ qWarning("get login token failed: %s\n", error.toString().toUtf8().data());
+ // server doesn't support client directly login, or other errors happened.
+ // We open the server url directly in this case;
+ QDesktopServices::openUrl(req->account().getAbsoluteUrl(req->nextUrl()));
+ req->deleteLater();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_AUTO_LOGIN_SERVICE_H_
+#define SEAFILE_CLIENT_AUTO_LOGIN_SERVICE_H_
+
+#include <QObject>
+#include <QString>
+
+#include "utils/singleton.h"
+
+class ApiError;
+
+class AutoLoginService : public QObject {
+ SINGLETON_DEFINE(AutoLoginService)
+ Q_OBJECT
+public:
+ AutoLoginService(QObject *parent=0);
+ // Get a auto login token from server, and then open the "next_url" after login
+
+public slots:
+ void startAutoLogin(const QString& next_url);
+
+private slots:
+ void onGetLoginTokenSuccess(const QString& token);
+ void onGetLoginTokenFailed(const ApiError& error);
+};
+
+#endif // SEAFILE_CLIENT_AUTO_LOGIN_SERVICE_H_
--- /dev/null
+#include <QSettings>
+
+#ifdef Q_OS_WIN32
+ #include <winsparkle.h>
+#else
+ #include "mac-sparkle-support.h"
+#endif
+
+#include "i18n.h"
+#include "api/requests.h"
+#include "seafile-applet.h"
+#include "utils/utils.h"
+
+#include "auto-update-service.h"
+
+SINGLETON_IMPL(AutoUpdateService)
+
+namespace
+{
+#ifdef Q_OS_WIN32
+ const char *kSparkleAppcastURI = "https://www.seafile.com/api/client-updates/seafile-client-windows/appcast.xml";
+ const char *kSparkleAppcastURIForCN = "https://www.seafile.com/api/client-updates/seafile-client-windows-cn/appcast.xml";
+ const char *kWinSparkleRegistryPath = "SOFTWARE\\Seafile\\Seafile Client\\WinSparkle";
+#else
+ const char *kSparkleAppcastURI = "https://www.seafile.com/api/client-updates/seafile-client-mac/appcast.xml";
+ const char *kSparkleAppcastURIForCN = "https://www.seafile.com/api/client-updates/seafile-client-mac-cn/appcast.xml";
+#endif
+ const char *kSparkleAlreadyEnableUpdateByDefault = "SparkleAlreadyEnableUpdateByDefault";
+ const char *kPreconfigureEnableAutoUpdate = "PreconfigureEnableAutoUpdate";
+
+QString getAppcastURI() {
+ QString url_from_env = qgetenv("SEAFILE_CLIENT_APPCAST_URI");
+ if (!url_from_env.isEmpty()) {
+ qWarning(
+ "winsparkle: using app cast url from SEAFILE_CLIENT_APPCAST_URI: "
+ "%s",
+ url_from_env.toUtf8().data());
+ return url_from_env;
+ }
+ return I18NHelper::getInstance()->isChinese() ? kSparkleAppcastURIForCN : kSparkleAppcastURI;
+}
+
+} // namespace
+
+// Virtual base class for windows/mac
+class AutoUpdateAdapter {
+public:
+ virtual void prepare() = 0;
+ virtual void start() = 0;
+ virtual void stop() = 0;
+ virtual void checkNow() = 0;
+ virtual bool autoUpdateEnabled() = 0;
+ virtual void setAutoUpdateEnabled(bool enabled) = 0;
+};
+
+#ifdef Q_OS_WIN32
+class WindowsAutoUpdateAdapter: public AutoUpdateAdapter {
+public:
+ void prepare() {
+ // Note that @param path is relative to HKCU/HKLM root
+ // and the root is not part of it. For example:
+ // @code
+ // win_sparkle_set_registry_path("Software\\My App\\Updates");
+ // @endcode
+ win_sparkle_set_registry_path(kWinSparkleRegistryPath);
+ win_sparkle_set_appcast_url(getAppcastURI().toUtf8().data());
+ win_sparkle_set_app_details(
+ L"Seafile",
+ L"Seafile Client",
+ QString(STRINGIZE(SEAFILE_CLIENT_VERSION)).toStdWString().c_str());
+ }
+
+ void start() {
+ win_sparkle_init();
+ }
+
+ void stop() {
+ win_sparkle_cleanup();
+ }
+
+ void checkNow() {
+ win_sparkle_check_update_with_ui();
+ }
+
+ bool autoUpdateEnabled() {
+ // qWarning() << "autoUpdateEnabled =" << win_sparkle_get_automatic_check_for_updates();
+ return win_sparkle_get_automatic_check_for_updates();
+ }
+
+ void setAutoUpdateEnabled(bool enabled) {
+ win_sparkle_set_automatic_check_for_updates(enabled ? 1 : 0);
+ }
+};
+#elif defined(Q_OS_MAC)
+class MacAutoUpdateAdapter: public AutoUpdateAdapter {
+public:
+ void prepare() {
+ SparkleHelper::setFeedURL(getAppcastURI().toUtf8().data());
+ }
+
+ void start() {
+ }
+
+ void stop() {
+ }
+
+ void checkNow() {
+ SparkleHelper::checkForUpdate();
+ }
+
+ bool autoUpdateEnabled() {
+ return SparkleHelper::autoUpdateEnabled();
+ }
+
+ void setAutoUpdateEnabled(bool enabled) {
+ SparkleHelper::setAutoUpdateEnabled(enabled);
+ }
+};
+#endif
+
+
+AutoUpdateService::AutoUpdateService(QObject *parent) : QObject(parent)
+{
+#ifdef Q_OS_WIN32
+ adapter_ = new WindowsAutoUpdateAdapter;
+#else
+ adapter_ = new MacAutoUpdateAdapter;
+#endif
+}
+
+void AutoUpdateService::start()
+{
+ adapter_->prepare();
+ enableUpdateByDefault();
+ adapter_->start();
+}
+
+void AutoUpdateService::enableUpdateByDefault() {
+ // Enable auto update check by default.
+ QSettings settings;
+ settings.beginGroup("Misc");
+ bool already_enable_update_by_default = settings.value(kSparkleAlreadyEnableUpdateByDefault, false).toBool();
+#if defined(Q_OS_WIN32)
+ QString enable_auto_update = seafApplet->readPreconfigureExpandedString(kPreconfigureEnableAutoUpdate);
+
+ if (enable_auto_update == "1") {
+ setAutoUpdateEnabled(true);
+ } else if (enable_auto_update == "0") {
+ setAutoUpdateEnabled(false);
+ } else if (!already_enable_update_by_default && enable_auto_update.isEmpty()) {
+ settings.setValue(kSparkleAlreadyEnableUpdateByDefault, true);
+ setAutoUpdateEnabled(true);
+ }
+#else
+ if (!already_enable_update_by_default) {
+ settings.setValue(kSparkleAlreadyEnableUpdateByDefault, true);
+ setAutoUpdateEnabled(true);
+ }
+#endif
+
+ settings.endGroup();
+}
+
+void AutoUpdateService::stop()
+{
+ adapter_->stop();
+}
+
+
+void AutoUpdateService::checkUpdate()
+{
+ adapter_->checkNow();
+}
+
+
+bool AutoUpdateService::shouldSupportAutoUpdate() const {
+ // qWarning() << "shouldSupportAutoUpdate =" << (QString(getBrand()) == "Seafile");
+ return QString(getBrand()) == "Seafile";
+}
+
+bool AutoUpdateService::autoUpdateEnabled() const {
+ return adapter_->autoUpdateEnabled();
+}
+
+void AutoUpdateService::setAutoUpdateEnabled(bool enabled) {
+ // qWarning() << "setAutoUpdateEnabled:" << enabled;
+ adapter_->setAutoUpdateEnabled(enabled);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
+#define SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
+
+#include <QObject>
+#include <QString>
+
+#include "utils/singleton.h"
+
+class AutoUpdateAdapter;
+
+// Auto update seafile client program. Only used on windows/mac.
+class AutoUpdateService : public QObject
+{
+ SINGLETON_DEFINE(AutoUpdateService)
+ Q_OBJECT
+
+public:
+ AutoUpdateService(QObject *parent = 0);
+
+ bool shouldSupportAutoUpdate() const;
+
+ void setRequestParams();
+ bool autoUpdateEnabled() const;
+ void setAutoUpdateEnabled(bool enabled);
+
+ void start();
+ void stop();
+
+ void checkUpdate();
+
+private:
+ void enableUpdateByDefault();
+ QString getAppcastURI();
+ AutoUpdateAdapter *adapter_;
+};
+
+#endif // SEAFILE_CLIENT_AUTO_UPDATE_SERVICE_H
--- /dev/null
+#include <QDir>
+#include <QImage>
+#include <QQueue>
+#include <QHash>
+#include <QTimer>
+#include <QDateTime>
+
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "account-mgr.h"
+#include "api/requests.h"
+#include "utils/paint-utils.h"
+#include "utils/utils.h"
+
+#include <sqlite3.h>
+#include "avatar-service.h"
+
+namespace {
+
+const int kCheckPendingInterval = 1000; // 1s
+const char *kAvatarsDirName = "avatars";
+const qint64 kExpireTimeIntevalMsec = 300 * 1000; // 5min
+
+bool loadTimeStampCB(sqlite3_stmt *stmt, void* data)
+{
+ qint64* mtime = reinterpret_cast<qint64*>(data);
+
+ *mtime = sqlite3_column_int64(stmt, 0);
+
+ return true;
+}
+
+} // namespace
+
+const int AvatarService::kAvatarSize = 40;
+const int kAvatarSizeFromServer = 80;
+
+struct PendingRequestInfo {
+ int last_wait;
+ int time_to_wait;
+
+ void backoff() {
+ last_wait = qMax(last_wait, 1) * 2;
+ time_to_wait = last_wait;
+ }
+
+ bool isReady() {
+ return time_to_wait == 0;
+ }
+
+ void tick() {
+ time_to_wait = qMax(0, time_to_wait - 1);
+ }
+};
+
+class PendingAvatarRequestQueue
+{
+public:
+ PendingAvatarRequestQueue() {};
+
+ void enqueue(const QString& email) {
+ if (q_.contains(email)) {
+ return;
+ }
+ // if we have set an expire time, and we haven't reached it yet
+ if (expire_time_.contains(email) &&
+ QDateTime::currentMSecsSinceEpoch() <= expire_time_[email]) {
+ return;
+ }
+ // update expire time
+ expire_time_[email] = QDateTime::currentMSecsSinceEpoch() + kExpireTimeIntevalMsec;
+
+ q_.enqueue(email);
+ }
+
+ void enqueueAndBackoff(const QString& email) {
+ PendingRequestInfo& info = wait_[email];
+ info.backoff();
+
+ enqueue(email);
+ }
+
+ void clearWait(const QString& email) {
+ wait_.remove(email);
+ }
+
+ void tick() {
+ QListIterator<QString> iter(q_);
+
+ while (iter.hasNext()) {
+ QString email = iter.next();
+ if (wait_.contains(email)) {
+ PendingRequestInfo& info = wait_[email];
+ info.tick();
+ }
+ }
+ }
+
+ QString dequeue() {
+ int i = 0, n = q_.size();
+ while (i++ < n) {
+ if (q_.isEmpty()) {
+ return QString();
+ }
+
+ QString email = q_.dequeue();
+
+ PendingRequestInfo info = wait_.value(email);
+ if (info.isReady()) {
+ return email;
+ } else {
+ q_.enqueue(email);
+ }
+ }
+
+ return QString();
+ }
+
+ void reset() {
+ q_.clear();
+ wait_.clear();
+ expire_time_.clear();
+ }
+
+private:
+ QQueue<QString> q_;
+
+ QHash<QString, PendingRequestInfo> wait_;
+ QHash<QString, qint64> expire_time_;
+};
+
+AvatarService* AvatarService::singleton_;
+
+AvatarService* AvatarService::instance()
+{
+ if (singleton_ == NULL) {
+ static AvatarService instance;
+ singleton_ = &instance;
+ }
+
+ return singleton_;
+}
+
+
+AvatarService::AvatarService(QObject *parent)
+ : QObject(parent), get_avatar_req_(NULL)
+{
+ queue_ = new PendingAvatarRequestQueue;
+
+ timer_ = new QTimer(this);
+
+ connect(timer_, SIGNAL(timeout()), this, SLOT(checkPendingRequests()));
+
+ connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+ this, SLOT(onAccountChanged()));
+}
+
+void AvatarService::start()
+{
+ QDir seafile_dir(seafApplet->configurator()->seafileDir());
+
+ if (!seafile_dir.mkpath(kAvatarsDirName)) {
+ qWarning("Failed to create avatars folder");
+ QString err_msg = tr("Failed to create avatars folder");
+ seafApplet->errorAndExit(err_msg);
+ }
+
+ avatars_dir_ = seafile_dir.filePath(kAvatarsDirName);
+
+ do {
+ const char *errmsg;
+ QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
+ if (sqlite3_open (db_path.toUtf8().data(), &autoupdate_db_)) {
+ errmsg = sqlite3_errmsg (autoupdate_db_);
+ qWarning("failed to avatar autoupdate database %s: %s",
+ db_path.toUtf8().data(), errmsg ? errmsg : "no error given");
+
+ sqlite3_close(autoupdate_db_);
+ autoupdate_db_ = NULL;
+ break;
+ }
+
+ // enabling foreign keys, it must be done manually from each connection
+ // and this feature is only supported from sqlite 3.6.19
+ const char *sql = "PRAGMA foreign_keys=ON;";
+ if (sqlite_query_exec (autoupdate_db_, sql) < 0) {
+ qWarning("sqlite version is too low to support foreign key feature\n");
+ qWarning("feature avatar autoupdate is disabled\n");
+ sqlite3_close(autoupdate_db_);
+ autoupdate_db_ = NULL;
+ break;
+ }
+
+ // create Avatar table
+ sql = "CREATE TABLE IF NOT EXISTS Avatar ("
+ "filename TEXT PRIMARY KEY, timestamp BIGINT, "
+ "url VARCHAR(24), username VARCHAR(15), "
+ "FOREIGN KEY(url, username) REFERENCES Accounts(url, username) "
+ "ON DELETE CASCADE ON UPDATE CASCADE )";
+ if (sqlite_query_exec (autoupdate_db_, sql) < 0) {
+ qWarning("failed to create avatar table\n");
+ sqlite3_close(autoupdate_db_);
+ autoupdate_db_ = NULL;
+ }
+ } while (0);
+
+ timer_->start(kCheckPendingInterval);
+}
+
+// fist check in-memory-cache, then check saved image on disk
+QImage AvatarService::loadAvatarFromLocal(const QString& email)
+{
+ if (cache_.contains(email)) {
+ return cache_.value(email);
+ }
+
+ QImage ret;
+ if (avatarFileExists(email)) {
+ ret = QImage(getAvatarFilePath(email));
+ cache_[email] = ret;
+ }
+
+ return ret;
+}
+
+QString AvatarService::avatarPathForEmail(const Account& account, const QString& email)
+{
+ return QDir(avatars_dir_)
+ .filePath(::md5(account.serverUrl.host() + email + "/" +
+ QString::number(kAvatarSizeFromServer)));
+}
+
+void AvatarService::fetchImageFromServer(const QString& email)
+{
+ if (get_avatar_req_) {
+ if (email == get_avatar_req_->email()) {
+ return;
+ }
+ queue_->enqueue(email);
+ return;
+ }
+
+ if (!seafApplet->accountManager()->hasAccount())
+ return;
+ const Account& account = seafApplet->accountManager()->accounts().front();
+ // Why we initialize mtime to -1 instead of 0? Because sometimes
+ // the mtime returned by the server is 0, so we must initialize it
+ // to -1 as a special value to indicate there is no local cache
+ // for this avatar yet.
+ qint64 mtime = -1;
+
+ if (autoupdate_db_) {
+ char *zql = sqlite3_mprintf("SELECT timestamp FROM Avatar "
+ "WHERE filename = %Q",
+ avatarPathForEmail(account, email).toUtf8().data());
+ sqlite_foreach_selected_row(autoupdate_db_, zql, loadTimeStampCB, &mtime);
+ sqlite3_free(zql);
+ }
+
+ get_avatar_req_ = new GetAvatarRequest(account, email, mtime, kAvatarSizeFromServer);
+
+ connect(get_avatar_req_, SIGNAL(success(const QImage&)),
+ this, SLOT(onGetAvatarSuccess(const QImage&)));
+ connect(get_avatar_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetAvatarFailed(const ApiError&)));
+
+ get_avatar_req_->send();
+}
+
+void AvatarService::onGetAvatarSuccess(const QImage& img)
+{
+ if (!get_avatar_req_) {
+ return;
+ }
+
+ const QString email = get_avatar_req_->email();
+
+ // if no change? early return
+ if (img.isNull()) {
+ get_avatar_req_->deleteLater();
+ get_avatar_req_ = NULL;
+
+ queue_->clearWait(email);
+ return;
+ }
+
+ image_ = img;
+
+ cache_[email] = img;
+
+ // save image to avatars/ folder
+ QString path = avatarPathForEmail(get_avatar_req_->account(), email);
+ if (!img.save(path, "PNG")) {
+ qWarning("Unable to save new avatar file %s", path.toUtf8().data());
+ }
+
+ // update cache db
+ if (autoupdate_db_) {
+ QString mtime = QString::number(get_avatar_req_->mtime());
+ char *zql = sqlite3_mprintf(
+ "REPLACE INTO Avatar(filename, timestamp, url, username) "
+ "VALUES (%Q, %Q, %Q, %Q)",
+ path.toUtf8().data(),
+ mtime.toUtf8().data(),
+ get_avatar_req_->account().serverUrl.toEncoded().data(),
+ get_avatar_req_->account().username.toUtf8().data());
+ sqlite_query_exec(autoupdate_db_, zql);
+ sqlite3_free(zql);
+ }
+
+ emit avatarUpdated(email, img);
+
+ get_avatar_req_->deleteLater();
+ get_avatar_req_ = NULL;
+
+ queue_->clearWait(email);
+}
+
+void AvatarService::onGetAvatarFailed(const ApiError& error)
+{
+ if (!get_avatar_req_) {
+ return;
+ }
+ const QString email = get_avatar_req_->email();
+ get_avatar_req_->deleteLater();
+ get_avatar_req_ = NULL;
+
+ queue_->enqueueAndBackoff(email);
+}
+
+QImage AvatarService::getAvatar(const QString& email)
+{
+ QImage img = loadAvatarFromLocal(email);
+
+ // TODO: check the timestamp of the cached avatar and update it if too old,
+ // e.g. cached more than one hour ago. We use timestamps when asking the
+ // server for avatars so updating avatars should be a light weight
+ // operation.
+
+ // update all avatars if feature autoupdate enabled or img is null
+ if (autoupdate_db_ || img.isNull()) {
+ if (!get_avatar_req_ || get_avatar_req_->email() != email) {
+ queue_->enqueue(email);
+ }
+ }
+ if (img.isNull()) {
+ return QImage(":/images/account.png");
+ } else {
+ return img;
+ }
+}
+
+QString AvatarService::getAvatarFilePath(const QString& email)
+{
+ const Account& account = seafApplet->accountManager()->accounts().front();
+ return avatarPathForEmail(account, email);
+}
+
+bool AvatarService::avatarFileExists(const QString& email)
+{
+ QString path = getAvatarFilePath(email);
+ bool ret = QFileInfo(path).exists();
+
+ if (!ret) {
+ char *zql = sqlite3_mprintf("DELETE FROM Avatar WHERE filename = %Q", path.toUtf8().data());
+ sqlite_query_exec (autoupdate_db_, zql);
+ sqlite3_free(zql);
+ }
+ return ret;
+}
+
+void AvatarService::checkPendingRequests()
+{
+ queue_->tick();
+
+ if (get_avatar_req_ != NULL) {
+ return;
+ }
+
+ QString email = queue_->dequeue();
+ if (!email.isEmpty()) {
+ fetchImageFromServer(email);
+ }
+}
+
+void AvatarService::onAccountChanged()
+{
+ queue_->reset();
+ if (get_avatar_req_) {
+ get_avatar_req_->deleteLater();
+ get_avatar_req_ = NULL;
+ }
+ cache_.clear();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_AVATAR_SERVICE_H
+#define SEAFILE_CLIENT_AVATAR_SERVICE_H
+
+#include <vector>
+#include <QObject>
+#include <QImage>
+#include <QHash>
+#include <QString>
+
+class QImage;
+class QTimer;
+
+class Account;
+class ApiError;
+class GetAvatarRequest;
+class PendingAvatarRequestQueue;
+
+struct sqlite3;
+
+class AvatarService : public QObject
+{
+ Q_OBJECT
+public:
+ static AvatarService* instance();
+
+ void start();
+
+ QImage getAvatar(const QString& email);
+
+ static const int kAvatarSize;
+
+signals:
+ void avatarUpdated(const QString& email, const QImage& avatar);
+
+private slots:
+ void onGetAvatarSuccess(const QImage& img);
+ void onGetAvatarFailed(const ApiError& error);
+ void checkPendingRequests();
+ void onAccountChanged();
+
+private:
+ Q_DISABLE_COPY(AvatarService)
+
+ AvatarService(QObject *parent=0);
+
+ static AvatarService *singleton_;
+
+ QImage loadAvatarFromLocal(const QString& email);
+ void fetchImageFromServer(const QString& email);
+ QString avatarPathForEmail(const Account& account, const QString& email);
+ QString getAvatarFilePath(const QString& email);
+ bool avatarFileExists(const QString& email);
+
+ GetAvatarRequest *get_avatar_req_;
+
+ QString avatars_dir_;
+
+ QImage image_;
+
+ QHash<QString, QImage> cache_;
+
+ PendingAvatarRequestQueue *queue_;
+
+ QTimer *timer_;
+
+ struct sqlite3 *autoupdate_db_;
+};
+
+
+#endif // SEAFILE_CLIENT_AVATAR_SERVICE_H
--- /dev/null
+#include <sqlite3.h>
+#include <glib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <algorithm>
+
+#include <QUrl>
+#include <QObject>
+
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "utils/utils.h"
+
+#include "certs-mgr.h"
+
+namespace {
+
+QString
+certToBase64(const QSslCertificate& cert)
+{
+ QByteArray bytes = cert.toPem();
+ return bytes.toBase64();
+}
+
+QSslCertificate
+certFromBase64(const char *data)
+{
+ QSslCertificate cert;
+ if (!data) {
+ return cert;
+ }
+
+ QByteArray bytes = QByteArray::fromBase64(data);
+
+ cert = QSslCertificate(bytes);
+
+ return cert;
+}
+
+// Remove path and query params from url before converting to string
+QString urlToString(const QUrl& url)
+{
+ QUrl u;
+
+ u.setScheme(url.scheme());
+ u.setHost(url.host());
+ u.setPort(url.port());
+
+ return u.toString();
+}
+
+} // namespace
+
+CertsManager::CertsManager()
+{
+ db = NULL;
+}
+
+CertsManager::~CertsManager()
+{
+ if (db)
+ sqlite3_close(db);
+}
+
+int
+CertsManager::start()
+{
+ const char *errmsg;
+ const char *sql;
+
+ QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("certs.db");
+ if (sqlite3_open (toCStr(db_path), &db)) {
+ errmsg = sqlite3_errmsg (db);
+ qWarning("failed to open certs database %s: %s",
+ toCStr(db_path), errmsg ? errmsg : "no error given");
+
+ seafApplet->errorAndExit(QObject::tr("failed to open certs database"));
+ return -1;
+ }
+
+ sql = "CREATE TABLE IF NOT EXISTS Certs ("
+ "url VARCHAR(255) PRIMARY KEY, "
+ "cert TEXT"
+ ")";
+ sqlite_query_exec (db, sql);
+
+ loadCertificates();
+ return 0;
+}
+
+bool CertsManager::loadCertificatesCB(sqlite3_stmt *stmt, void *data)
+{
+ CertsManager *mgr = (CertsManager *)data;
+ const char *url = (const char *)sqlite3_column_text (stmt, 0);
+ const char *base64 = (const char *)sqlite3_column_text(stmt, 1);
+
+ QSslCertificate cert = certFromBase64(base64);
+ if (!cert.isNull()) {
+ mgr->certs_[url] = cert;
+ }
+
+ return true;
+}
+
+void CertsManager::loadCertificates()
+{
+ const char *sql = "SELECT url, cert FROM Certs";
+ sqlite_foreach_selected_row (db, sql, loadCertificatesCB, this);
+}
+
+void
+CertsManager::saveCertificate(const QUrl& url, const QSslCertificate& cert)
+{
+ QString key = urlToString(url);
+ certs_[key] = cert;
+
+ QString sql = "REPLACE INTO Certs VALUES ('%1', '%2')";
+ sql = sql.arg(key).arg(certToBase64(cert));
+ sqlite_query_exec (db, toCStr(sql));
+}
+
+QSslCertificate
+CertsManager::getCertificate(const QUrl& url)
+{
+ QString key = urlToString(url);
+
+ if (certs_.contains(key)) {
+ return certs_[key];
+ }
+ QSslCertificate cert;
+ return cert;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CERTS_MANAGER_H
+#define SEAFILE_CLIENT_CERTS_MANAGER_H
+
+#include <QHash>
+#include <QSslCertificate>
+
+struct sqlite3;
+struct sqlite3_stmt;
+
+class QUrl;
+
+class CertsManager {
+public:
+ CertsManager();
+ ~CertsManager();
+
+ int start();
+
+ void saveCertificate(const QUrl& url, const QSslCertificate& cert);
+ QSslCertificate getCertificate(const QUrl& url);
+
+private:
+ void loadCertificates();
+ static bool loadCertificatesCB(sqlite3_stmt *stmt, void *data);
+
+ QHash<QString, QSslCertificate> certs_;
+
+ struct sqlite3 *db;
+};
+
+#endif // SEAFILE_CLIENT_CERTS_MANAGER_H
--- /dev/null
+#include <glib.h>
+#include <QCoreApplication>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QDebug>
+#include <QList>
+#include <QMessageBox>
+#include <QSettings>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "ui/init-seafile-dialog.h"
+
+#if defined(Q_OS_WIN32)
+#include "utils/registry.h"
+#include <shlobj.h>
+#include <shlwapi.h>
+#endif
+
+#include "configurator.h"
+
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kVirtualDriveGUID = "F817C393-A76E-435E-B6B1-485844BC9C2E";
+const char *kMyComputerNamespacePath =
+ "Software\\Microsoft\\Windows\\CurrentVersion"
+ "\\Explorer\\MyComputer\\Namespace";
+#endif
+
+const char* const kPreconfigureDirectory = "PreconfigureDirectory";
+
+inline QString getPreconfigureDirectory()
+{
+ return expandVars(expandUser(seafApplet->readPreconfigureEntry(kPreconfigureDirectory).toString()));
+}
+
+} // namespace
+
+
+Configurator::Configurator()
+ : ccnet_dir_(defaultCcnetDir()),
+ first_use_(false)
+{
+}
+
+void Configurator::checkInit()
+{
+ if (needInitConfig()) {
+ // first time use
+ initConfig();
+ } else {
+ validateExistingConfig();
+ }
+}
+
+bool Configurator::needInitConfig()
+{
+ if (QDir(ccnet_dir_).exists()) {
+ return false;
+ }
+
+ return true;
+}
+
+void Configurator::initConfig()
+{
+ QString path = QDir::toNativeSeparators(ccnet_dir_);
+ QDir ccnet_dir(ccnet_dir_);
+ if (!ccnet_dir.mkpath(".")) {
+ seafApplet->errorAndExit(tr("Error when creating ccnet configuration"));
+ return;
+ }
+
+ first_use_ = true;
+ initSeafile();
+}
+
+void Configurator::initSeafile()
+{
+ QString preconfigure_dir = getPreconfigureDirectory();
+ if (!preconfigure_dir.isEmpty()) {
+ QDir dir(preconfigure_dir);
+ if (!dir.mkpath(".") ||
+ !dir.mkpath("Seafile/.seafile-data")) {
+ qWarning("[Configurator] unable to create preconfigure directory \"%s\"",
+ preconfigure_dir.toUtf8().data());
+ qWarning("[Configurator] exiting from an unrecovable error.");
+ seafApplet->warningBox(
+ tr("Unable to create preconfigure directory \"%1\"").arg(
+ preconfigure_dir.toUtf8().data()));
+ exit(1);
+ return;
+ }
+ first_use_ = true;
+
+ QString seafile_dir = dir.absoluteFilePath("Seafile/.seafile-data");
+ onSeafileDirSet(seafile_dir);
+ return;
+ }
+ InitSeafileDialog dialog;
+ connect(&dialog, SIGNAL(seafileDirSet(const QString&)),
+ this, SLOT(onSeafileDirSet(const QString&)));
+
+ if (dialog.exec() != QDialog::Accepted) {
+ exit(1);
+ return;
+ }
+
+ first_use_ = true;
+}
+
+void Configurator::onSeafileDirSet(const QString& path)
+{
+ // Write seafile dir to <ccnet dir>/seafile.ini
+ QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
+
+ if (!seafile_ini.open(QIODevice::WriteOnly)) {
+ return;
+ }
+
+ seafile_ini.write(path.toUtf8().data());
+
+ seafile_dir_ = path;
+
+ QDir d(path);
+
+ d.cdUp();
+ worktree_ = d.absolutePath();
+
+ setSeafileDirAttributes();
+}
+
+void Configurator::setSeafileDirAttributes()
+{
+#if defined(Q_OS_WIN32)
+ std::wstring seafdir = seafile_dir_.toStdWString();
+
+ // Make seafile-data folder hidden
+ SetFileAttributesW (seafdir.c_str(),
+ FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+
+ // Set seafdir folder icon.
+ SetFileAttributesW (worktree_.toStdWString().c_str(), FILE_ATTRIBUTE_SYSTEM);
+ QString desktop_ini_path = QDir(worktree_).filePath("Desktop.ini");
+ QFile desktop_ini(desktop_ini_path);
+
+ if (!desktop_ini.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ return;
+ }
+
+ // QString icon_path = QDir(QCoreApplication::applicationDirPath()).filePath("seafdir.ico");
+
+ // QTextStream out(&desktop_ini);
+ // out << "[.ShellClassInfo]\n";
+ // out << QString("IconFile=%1\n").arg(icon_path);
+ // out << "IconIndex=0\n";
+
+ // // Make the "Desktop.ini" file hidden.
+ // SetFileAttributesW (desktop_ini_path.toStdWString().c_str(),
+ // FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+#endif
+}
+
+void Configurator::validateExistingConfig()
+{
+ QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
+ if (!seafile_ini.exists()) {
+ initConfig();
+ return;
+ }
+
+ if (readSeafileIni(&seafile_dir_) < 0 || !QDir(seafile_dir_).exists()) {
+ initSeafile();
+ return;
+ }
+
+ QDir d(seafile_dir_);
+#if !defined(Q_OS_WIN32)
+ QString old_client_wt = d.filePath("../seafile/");
+ if (QFile(old_client_wt).exists()) {
+ // old client
+ worktree_ = QFileInfo(old_client_wt).absoluteFilePath();
+ return;
+ }
+#endif
+
+ d.cdUp();
+ worktree_ = d.absolutePath();
+}
+
+int Configurator::readSeafileIni(QString *content)
+{
+ // First try SEAFILE_DATA_DIR
+ const char *env = g_getenv("SEAFILE_DATA_DIR");
+ if (env) {
+ *content = QString::fromUtf8(env);
+ return 0;
+ }
+
+ QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
+ if (!seafile_ini.exists()) {
+ return -1;
+ }
+
+ if (!seafile_ini.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ seafApplet->errorAndExit(tr("failed to read %1").arg(seafile_ini.fileName()));
+ }
+
+ QTextStream input(&seafile_ini);
+ input.setCodec("UTF-8");
+
+ if (input.atEnd()) {
+ return -1;
+ }
+
+ *content = input.readLine();
+
+ return 0;
+}
+
+void Configurator::installCustomUrlHandler()
+{
+#if defined(Q_OS_WIN32)
+ QList<RegElement> list;
+ HKEY root = HKEY_CURRENT_USER;
+
+ QString exe = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());
+
+ QString cmd = QString("\"%1\" -f ").arg(exe) + " \"%1\"";
+
+ QString classes_seafile = "Software\\Classes\\seafile";
+
+ list.append(RegElement(root, classes_seafile,
+ "", "URL:seafile Protocol"));
+
+ list.append(RegElement(root, classes_seafile,
+ "URL Protocol", ""));
+
+ list.append(RegElement(root, classes_seafile + "\\shell",
+ "", ""));
+
+ list.append(RegElement(root, classes_seafile + "\\shell\\open",
+ "", ""));
+
+ list.append(RegElement(root, classes_seafile + "\\shell\\open\\command",
+ "", cmd));
+ for (int i = 0; i < list.size(); i++) {
+ RegElement& reg = list[i];
+ reg.add();
+ }
+#endif
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CONFIGURATOR_H
+#define SEAFILE_CLIENT_CONFIGURATOR_H
+
+#include <QObject>
+#include <QString>
+
+/**
+ * Handles seafile configuration initialize
+ */
+class Configurator : public QObject {
+ Q_OBJECT
+
+public:
+ Configurator();
+
+ void checkInit();
+
+ const QString& ccnetDir() const { return ccnet_dir_; }
+ const QString& seafileDir() const { return seafile_dir_; }
+ const QString& worktreeDir() const { return worktree_; }
+ const QString& defaultRepoPath() const { return default_repo_path_; }
+
+ bool firstUse() const { return first_use_; }
+
+public:
+ static void installCustomUrlHandler();
+
+private slots:
+ void onSeafileDirSet(const QString& path);
+
+private:
+ Q_DISABLE_COPY(Configurator)
+
+ void setSeafileDirAttributes();
+
+ bool needInitConfig();
+ void initConfig();
+ void validateExistingConfig();
+ int readSeafileIni(QString *content);
+
+ void initCcnet();
+ void initSeafile();
+
+ QString ccnet_dir_;
+ QString seafile_dir_;
+ QString worktree_;
+
+ QString default_repo_path_;
+
+ bool first_use_;
+};
+
+#endif // SEAFILE_CLIENT_CONFIGURATOR_H
--- /dev/null
+#include "crash-handler.h"
+#include <QDir>
+#include <QString>
+#include <cstdio>
+
+#if defined(Q_OS_LINUX)
+#include "breakpad/client/linux/handler/exception_handler.h"
+#elif defined(Q_OS_WIN32)
+#include "breakpad/client/windows/handler/exception_handler.h"
+#elif defined(Q_OS_MAC)
+#include "breakpad/client/mac/handler/exception_handler.h"
+#endif
+
+namespace Breakpad {
+/************************************************************************/
+/* CrashHandlerPrivate */
+/************************************************************************/
+class CrashHandlerPrivate
+{
+public:
+ CrashHandlerPrivate() {}
+ ~CrashHandlerPrivate() { delete handler; }
+
+ void InitCrashHandler(const QString& dumpPath);
+
+#if defined(Q_OS_WIN32)
+ static bool DumpCallback(const wchar_t* _dump_dir,
+ const wchar_t* _minidump_id,
+ void* context,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ bool success);
+#elif defined(Q_OS_LINUX)
+ static bool DumpCallback(const google_breakpad::MinidumpDescriptor &md,
+ void *context,
+ bool success);
+#elif defined(Q_OS_MAC)
+ static bool DumpCallback(const char* _dump_dir,
+ const char* _minidump_id,
+ void *context,
+ bool success);
+#endif
+
+ static google_breakpad::ExceptionHandler* handler;
+};
+
+
+google_breakpad::ExceptionHandler* CrashHandlerPrivate::handler = NULL;
+
+#if defined(Q_OS_WIN32)
+bool CrashHandlerPrivate::DumpCallback(const wchar_t* _dump_dir,
+ const wchar_t* _minidump_id,
+ void* context,
+ EXCEPTION_POINTERS* exinfo,
+ MDRawAssertionInfo* assertion,
+ bool success)
+#elif defined(Q_OS_LINUX)
+bool CrashHandlerPrivate::DumpCallback(const google_breakpad::MinidumpDescriptor &md,
+ void *context,
+ bool success)
+#elif defined(Q_OS_MAC)
+bool CrashHandlerPrivate::DumpCallback(const char* _dump_dir,
+ const char* _minidump_id,
+ void *context,
+ bool success)
+#endif
+{
+ Q_UNUSED(context);
+#if defined(Q_OS_WIN32)
+ Q_UNUSED(_dump_dir);
+ Q_UNUSED(_minidump_id);
+ Q_UNUSED(assertion);
+ Q_UNUSED(exinfo);
+#endif
+ fprintf(stderr, "[breakpad] crash detected\n");
+ /*
+ * unsafe context
+ * don't allocate memory by heap
+ *
+ */
+
+ // CrashHandlerPrivate* self = static_cast<CrashHandlerPrivate*>(context);
+
+ if (!success) {
+ fprintf(stderr, "Failed to generate minidump.\n");
+ return false;
+ }
+
+ fprintf(stderr, "[breakpad] minidump generated\n");
+
+ return success;
+}
+
+ void CrashHandlerPrivate::InitCrashHandler(const QString& dumpPath)
+ {
+ if (handler != NULL)
+ return;
+
+#if defined(Q_OS_WIN32)
+ std::wstring pathAsStr = (const wchar_t*)dumpPath.utf16();
+ handler = new google_breakpad::ExceptionHandler(
+ pathAsStr,
+ /*FilterCallback*/ 0,
+ DumpCallback,
+ /*context*/ this,
+ true
+ );
+#elif defined(Q_OS_LINUX)
+ std::string pathAsStr = dumpPath.toStdString();
+ google_breakpad::MinidumpDescriptor md(pathAsStr);
+ handler = new google_breakpad::ExceptionHandler(
+ md,
+ /*FilterCallback*/ 0,
+ DumpCallback,
+ /*context*/ this,
+ true,
+ -1
+ );
+#elif defined(Q_OS_MAC)
+ std::string pathAsStr = dumpPath.toStdString();
+ handler = new google_breakpad::ExceptionHandler(
+ pathAsStr,
+ /*FilterCallback*/ 0,
+ DumpCallback,
+ /*context*/ this,
+ true,
+ google_breakpad::ExceptionHandler::HANDLER_ALL
+ );
+#endif
+ fprintf(stderr, "[breakpad] initialized\n");
+ }
+
+ /************************************************************************/
+ /* CrashHandler */
+ /************************************************************************/
+ CrashHandler* CrashHandler::instance()
+ {
+ static CrashHandler globalHandler;
+ return &globalHandler;
+ }
+
+ CrashHandler::CrashHandler()
+ {
+ d = new CrashHandlerPrivate();
+ }
+
+ CrashHandler::~CrashHandler()
+ {
+ delete d;
+ }
+
+ void CrashHandler::Init(const QString& reportPath)
+ {
+ if (!QDir(reportPath).mkpath("."))
+ fprintf(stderr, "[breakpad] failed to create crash directory\n");
+ d->InitCrashHandler(reportPath);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CRASH_HANDLER
+#define SEAFILE_CLIENT_CRASH_HANDLER
+#ifdef SEAFILE_CLIENT_HAS_CRASH_REPORTER
+#include <QString>
+
+namespace Breakpad {
+
+class CrashHandlerPrivate;
+class CrashHandler
+{
+public:
+ static CrashHandler* instance();
+ void Init(const QString& reportPath);
+private:
+ Q_DISABLE_COPY(CrashHandler)
+
+ CrashHandler();
+ ~CrashHandler();
+ CrashHandlerPrivate* d;
+};
+}
+#endif // SEAFILE_CLIENT_HAS_CRASH_REPORTER
+#endif // SEAFILE_CLIENT_CRASH_HANDLER
+
--- /dev/null
+#include <QTimer>
+#include <QDir>
+#include <QNetworkDiskCache>
+
+#include "customization-service.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "configurator.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+
+
+SINGLETON_IMPL(CustomizationService)
+
+CustomizationService::CustomizationService(QObject* parent) : QObject(parent)
+{
+ disk_cache_ = new QNetworkDiskCache();
+}
+
+void CustomizationService::start()
+{
+ disk_cache_->setCacheDirectory(
+ QDir(seafApplet->configurator()->seafileDir())
+ .filePath("customization"));
+}
+
+QPixmap CustomizationService::getServerLogo(const Account& account)
+{
+ QPixmap logo = QPixmap(":/images/seafile-24.png");
+ if (account.serverInfo.customLogo.isEmpty()) {
+ return logo;
+ }
+
+ QUrl url = account.getAbsoluteUrl(account.serverInfo.customLogo);
+ QIODevice* buf = disk_cache_->data(url);
+ if (buf) {
+ logo.loadFromData(buf->readAll());
+ buf->close();
+ delete buf;
+ }
+
+ if (!reqs_.contains(url.toString())) {
+ FetchCustomLogoRequest* req = new FetchCustomLogoRequest(url);
+ connect(req,
+ SIGNAL(success(const QUrl&)),
+ this,
+ SLOT(onServerLogoFetched(const QUrl&)));
+ connect(req,
+ SIGNAL(failed(const ApiError&)),
+ this,
+ SLOT(onServerLogoFetchFailed(const ApiError&)));
+
+ req->send();
+ reqs_[url.toString()] = req;
+ }
+
+ return logo;
+}
+
+void CustomizationService::onServerLogoFetched(const QUrl& url)
+{
+ emit(serverLogoFetched(url));
+ FetchCustomLogoRequest* req =
+ qobject_cast<FetchCustomLogoRequest*>(sender());
+ cleanUpRequest(req);
+}
+
+void CustomizationService::onServerLogoFetchFailed(const ApiError& error)
+{
+ FetchCustomLogoRequest* req =
+ qobject_cast<FetchCustomLogoRequest*>(sender());
+ cleanUpRequest(req);
+}
+
+void CustomizationService::cleanUpRequest(FetchCustomLogoRequest* req)
+{
+ reqs_.remove(req->url().toString());
+ req->deleteLater();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CUSTOMIAZATION_SERVICE_H
+#define SEAFILE_CLIENT_CUSTOMIAZATION_SERVICE_H
+
+#include <QObject>
+#include <QUrl>
+#include <QPixmap>
+#include <QHash>
+
+#include "utils/singleton.h"
+#include "account.h"
+
+class QNetworkDiskCache;
+
+class FetchCustomLogoRequest;
+class ApiError;
+
+class CustomizationService : public QObject
+{
+ Q_OBJECT
+ SINGLETON_DEFINE(CustomizationService)
+public:
+ void start();
+
+ // Read the logo from the disk cache if exists, otherwise return a default
+ // logo and send a request to fetch the logo.
+ QPixmap getServerLogo(const Account& account);
+
+ QNetworkDiskCache *diskCache() const { return disk_cache_; }
+
+signals:
+ void serverLogoFetched(const QUrl& url);
+
+private slots:
+ void onServerLogoFetched(const QUrl& url);
+ void onServerLogoFetchFailed(const ApiError& error);
+
+private:
+ Q_DISABLE_COPY(CustomizationService)
+ CustomizationService(QObject* parent = 0);
+
+ void cleanUpRequest(FetchCustomLogoRequest *req);
+
+ QHash<QString, FetchCustomLogoRequest*> reqs_;
+
+ QNetworkDiskCache* disk_cache_;
+};
+
+
+#endif // SEAFILE_CLIENT_CUSTOMIAZATION_SERVICE_H
--- /dev/null
+#include <glib-object.h>
+#include <cstdio>
+#include <cstdlib>
+#include <QTimer>
+#include <QStringList>
+#include <QString>
+#include <QDebug>
+#include <QDir>
+#include <QCoreApplication>
+
+#include "utils/utils.h"
+#include "utils/process.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "daemon-mgr.h"
+
+namespace {
+
+const int kConnDaemonIntervalMilli = 1000;
+const int kMaxDaemonReadyCheck = 15;
+
+const int kDaemonRestartInternvalMSecs = 2000;
+const int kDaemonRestartMaxRetries = 10;
+
+#if defined(Q_OS_WIN32)
+const char *kSeafileDaemonExecutable = "seaf-daemon.exe";
+#else
+const char *kSeafileDaemonExecutable = "seaf-daemon";
+#endif
+
+typedef enum {
+ DAEMON_INIT = 0,
+ DAEMON_STARTING,
+ DAEMON_CONNECTING,
+ DAEMON_CONNECTED,
+ DAEMON_DEAD,
+ SEAFILE_EXITING,
+ MAX_STATE,
+} DaemonState;
+
+const char *DaemonStateStrs[] = {
+ "init",
+ "starting",
+ "connecting",
+ "connected",
+ "dead",
+ "seafile_exiting"
+};
+
+const char *stateToStr(int state)
+{
+ if (state < 0 || state >= MAX_STATE) {
+ return "";
+ }
+ return DaemonStateStrs[state];
+}
+
+bool seafileRpcReady() {
+ SeafileRpcClient rpc;
+ if (!rpc.tryConnectDaemon()) {
+ return false;
+ }
+
+ QString str;
+ return rpc.seafileGetConfig("use_proxy", &str) == 0;
+}
+
+
+} // namespace
+
+
+
+DaemonManager::DaemonManager()
+ : seaf_daemon_(nullptr)
+{
+ current_state_ = DAEMON_INIT;
+ first_start_ = true;
+ restart_retried_ = 0;
+
+ conn_daemon_timer_ = new QTimer(this);
+ connect(conn_daemon_timer_, SIGNAL(timeout()), this, SLOT(checkDaemonReady()));
+
+ connect(qApp, SIGNAL(aboutToQuit()),
+ this, SLOT(systemShutDown()));
+}
+
+DaemonManager::~DaemonManager() {
+ stopDaemon();
+}
+
+void DaemonManager::restartSeafileDaemon()
+{
+ if (current_state_ == SEAFILE_EXITING) {
+ return;
+ }
+
+ qWarning("Trying to restart seafile daemon");
+ startSeafileDaemon();
+}
+
+void DaemonManager::startSeafileDaemon()
+{
+ if (first_start_) {
+ shutdown_process (kSeafileDaemonExecutable);
+ }
+
+ seaf_daemon_ = new QProcess(this);
+ connect(seaf_daemon_, SIGNAL(started()), this, SLOT(onDaemonStarted()));
+ connect(seaf_daemon_, SIGNAL(finished(int, QProcess::ExitStatus)),
+ SLOT(onDaemonFinished(int, QProcess::ExitStatus)));
+
+ const QString config_dir = seafApplet->configurator()->ccnetDir();
+ const QString seafile_dir = seafApplet->configurator()->seafileDir();
+ const QString worktree_dir = seafApplet->configurator()->worktreeDir();
+
+ QStringList args;
+ args << "-c" << config_dir << "-d" << seafile_dir << "-w" << worktree_dir;
+ seaf_daemon_->start(RESOURCE_PATH(kSeafileDaemonExecutable), args);
+ qWarning() << "starting seaf-daemon: " << args;
+ transitionState(DAEMON_STARTING);
+}
+
+void DaemonManager::systemShutDown()
+{
+ transitionState(SEAFILE_EXITING);
+}
+
+void DaemonManager::onDaemonStarted()
+{
+ qDebug("seafile daemon is now running, checking if the service is ready");
+ conn_daemon_timer_->start(kConnDaemonIntervalMilli);
+ transitionState(DAEMON_CONNECTING);
+}
+
+void DaemonManager::checkDaemonReady()
+{
+ QString str;
+ // Because some settings need to be loaded from seaf daemon, we only emit
+ // the "daemonStarted" signal after we're sure the daemon rpc is ready.
+ if (seafileRpcReady()) {
+ qDebug("seaf daemon is ready");
+ conn_daemon_timer_->stop();
+ transitionState(DAEMON_CONNECTED);
+ restart_retried_ = 0;
+ if (first_start_) {
+ first_start_ = false;
+ emit daemonStarted();
+ } else {
+ emit daemonRestarted();
+ }
+ return;
+ }
+ qDebug("seaf daemon is not ready");
+ static int maxcheck = 0;
+ if (++maxcheck > kMaxDaemonReadyCheck) {
+ qWarning("seafile rpc is not ready after %d retry, abort", maxcheck);
+ seafApplet->errorAndExit(tr("%1 client failed to initialize").arg(getBrand()));
+ }
+}
+
+void DaemonManager::onDaemonFinished(int exit_code, QProcess::ExitStatus exit_status)
+{
+ qWarning("Seafile daemon process %s with code %d ",
+ (current_state_ != SEAFILE_EXITING &&
+ exit_status == QProcess::CrashExit)
+ ? "crashed"
+ : "exited normally",
+ exit_code);
+
+
+ if (current_state_ == DAEMON_CONNECTING) {
+ conn_daemon_timer_->stop();
+ scheduleRestartDaemon();
+ } else if (current_state_ != SEAFILE_EXITING) {
+ transitionState(DAEMON_DEAD);
+ emit daemonDead();
+ scheduleRestartDaemon();
+ }
+}
+
+void DaemonManager::stopDaemon()
+{
+ conn_daemon_timer_->stop();
+ if (seaf_daemon_) {
+ qWarning("[Daemon Mgr] stopping seafile daemon");
+ // TODO: add an "exit" rpc in seaf-daemon to exit gracefully?
+ seaf_daemon_->kill();
+ seaf_daemon_->waitForFinished(50);
+ seaf_daemon_ = nullptr;
+ }
+}
+
+void DaemonManager::scheduleRestartDaemon()
+{
+ // When the daemon crashes when we first start seafile, we should
+ // not retry too many times, because during the retry nothing
+ // would be shown to the user and would confuse him.
+ int max_retry = 2;
+ if (seafApplet->rpcClient() && seafApplet->rpcClient()->isConnected()) {
+ max_retry = kDaemonRestartMaxRetries;
+ }
+ if (++restart_retried_ >= max_retry) {
+ qWarning("reaching max tries of restarting seafile daemon, aborting");
+ seafApplet->errorAndExit(tr("%1 exited unexpectedly").arg(getBrand()));
+ return;
+ }
+ QTimer::singleShot(kDaemonRestartInternvalMSecs, this, SLOT(restartSeafileDaemon()));
+}
+
+void DaemonManager::transitionState(int new_state)
+{
+ qDebug("daemon mgr: %s => %s", stateToStr(current_state_), stateToStr(new_state));
+ current_state_ = new_state;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_DAEMON_MANAGER_H
+#define SEAFILE_CLIENT_DAEMON_MANAGER_H
+
+#include <QObject>
+#include <QProcess>
+
+class QTimer;
+
+/**
+ * Start/Monitor seafile daemon
+ */
+class DaemonManager : public QObject {
+ Q_OBJECT
+
+public:
+ DaemonManager();
+ ~DaemonManager();
+ void startSeafileDaemon();
+
+signals:
+ void daemonStarted();
+
+ void daemonDead();
+ void daemonRestarted();
+
+private slots:
+ void onDaemonStarted();
+ void onDaemonFinished(int exit_code, QProcess::ExitStatus exit_status);
+ void systemShutDown();
+ void checkDaemonReady();
+ void restartSeafileDaemon();
+
+private:
+ Q_DISABLE_COPY(DaemonManager)
+
+ void stopDaemon();
+ void scheduleRestartDaemon();
+ void transitionState(int new_state);
+
+ QProcess *seaf_daemon_;
+ QTimer *conn_daemon_timer_;
+
+ int current_state_;
+ // Used to decide whether to emit daemonStarted or daemonRestarted
+ bool first_start_;
+ int restart_retried_;
+};
+
+#endif // SEAFILE_CLIENT_DAEMON_MANAGER_H
--- /dev/null
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/requests.h"
+#include "events-service.h"
+
+namespace {
+
+const int kEventsPerPageForNewApi = 25;
+} // namespace
+
+EventsService* EventsService::singleton_;
+
+EventsService* EventsService::instance()
+{
+ if (singleton_ == NULL) {
+ static EventsService instance;
+ singleton_ = &instance;
+ }
+
+ return singleton_;
+}
+
+EventsService::EventsService(QObject *parent)
+ : QObject(parent)
+{
+ get_events_req_ = NULL;
+ get_file_activities_req_ = NULL;
+ next_ = -1;
+ in_refresh_ = false;
+}
+
+void EventsService::start()
+{
+}
+
+void EventsService::stop()
+{
+}
+
+void EventsService::refresh()
+{
+ if (seafApplet->accountManager()->currentAccount().isPro()) {
+ sendRequest(false);
+ }
+}
+
+void EventsService::sendRequest(bool is_load_more)
+{
+ if (in_refresh_) {
+ return;
+ }
+
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ in_refresh_ = false;
+ return;
+ }
+
+ // server version begin 7.0.0 support new api
+ bool is_support_new_file_activities_api = account.isAtLeastVersion(7, 0, 0);
+ in_refresh_ = true;
+
+ if (!is_support_new_file_activities_api) {
+ if (get_events_req_) {
+ get_events_req_->deleteLater();
+ }
+
+ if (!is_load_more) {
+ events_.clear();
+ next_ = -1;
+ }
+
+ get_events_req_ = new GetEventsRequest(account, next_);
+
+ connect(get_events_req_, SIGNAL(success(const std::vector<SeafEvent>&, int)),
+ this, SLOT(onRefreshSuccess(const std::vector<SeafEvent>&, int)));
+
+ connect(get_events_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onRefreshFailed(const ApiError&)));
+
+ get_events_req_->send();
+ } else {
+ if (get_file_activities_req_) {
+ get_file_activities_req_->deleteLater();
+ }
+
+ if (!is_load_more) {
+ events_.clear();
+ next_ = 1;
+ } else {
+ ++next_;
+ }
+
+ get_file_activities_req_ = new GetEventsRequestV2(account, next_);
+
+ connect(get_file_activities_req_, SIGNAL(success(const std::vector<SeafEvent>&)),
+ this, SLOT(onRefreshSuccessV2(const std::vector<SeafEvent>&)));
+
+ connect(get_file_activities_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onRefreshFailed(const ApiError&)));
+
+ get_file_activities_req_->send();
+ }
+
+}
+
+void EventsService::loadMore()
+{
+ sendRequest(true);
+}
+
+void EventsService::onRefreshSuccess(const std::vector<SeafEvent>& events, int new_offset)
+{
+ in_refresh_ = false;
+
+ const std::vector<SeafEvent> new_events = handleEventsOffset(events);
+
+ bool is_loading_more = next_ > 0;
+ bool has_more = new_offset > 0;
+ next_ = new_offset;
+ emit refreshSuccess(new_events, is_loading_more, has_more);
+}
+
+void EventsService::onRefreshSuccessV2(const std::vector<SeafEvent>& events)
+{
+ in_refresh_ = false;
+
+ const std::vector<SeafEvent> new_events = handleEventsOffset(events);
+
+ bool has_more = events.size() == kEventsPerPageForNewApi;
+ bool is_loading_more = next_ > 1;
+ if (!has_more) {
+ next_ = -1;
+ }
+
+ emit refreshSuccess(new_events, is_loading_more, has_more);
+}
+
+// We use the "offset" param as the starting point of loading more events, but
+// if there are new events on the server, the offset would be inaccurate.
+const std::vector<SeafEvent>
+EventsService::handleEventsOffset(const std::vector<SeafEvent>& new_events)
+{
+ if (events_.empty()) {
+ events_ = new_events;
+ return events_;
+ }
+
+ const SeafEvent& last = events_[events_.size() - 1];
+
+ int i = 0, n = new_events.size();
+
+ for (i = 0; i < n; i++) {
+ const SeafEvent& event = new_events[i];
+ if (event.timestamp < last.timestamp) {
+ break;
+ } else if (event.commit_id == last.commit_id) {
+ continue;
+ } else {
+ continue;
+ }
+ }
+
+ std::vector<SeafEvent> ret;
+
+ while (i < n) {
+ SeafEvent event = new_events[i++];
+ events_.push_back(event);
+ ret.push_back(event);
+ }
+
+ return ret;
+}
+
+void EventsService::onRefreshFailed(const ApiError& error)
+{
+ in_refresh_ = false;
+
+ emit refreshFailed(error);
+}
+
+void EventsService::refresh(bool force)
+{
+ if (force) {
+ in_refresh_ = false;
+ }
+
+ refresh();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_EVENTS_SERVICE_H
+#define SEAFILE_CLIENT_EVENTS_SERVICE_H
+
+#include <vector>
+#include <QObject>
+
+#include "api/event.h"
+
+class ApiError;
+class GetEventsRequest;
+class GetEventsRequestV2;
+
+class EventsService : public QObject
+{
+ Q_OBJECT
+public:
+ static EventsService* instance();
+
+ void start();
+ void stop();
+
+ void refresh(bool force);
+
+ void loadMore();
+
+ // accessors
+ const std::vector<SeafEvent>& events() const { return events_; }
+
+ bool hasMore() const { return next_ > 0; }
+
+public slots:
+ void refresh();
+
+private slots:
+ void onRefreshSuccess(const std::vector<SeafEvent>& events, int more_offset);
+ void onRefreshSuccessV2(const std::vector<SeafEvent>& events);
+ void onRefreshFailed(const ApiError& error);
+
+signals:
+ void refreshSuccess(const std::vector<SeafEvent>& events, bool is_loading_more, bool has_more);
+ void refreshFailed(const ApiError& error);
+
+private:
+ Q_DISABLE_COPY(EventsService)
+
+ EventsService(QObject *parent=0);
+ void sendRequest(bool is_loading_more);
+
+ static EventsService *singleton_;
+
+ const std::vector<SeafEvent> handleEventsOffset(const std::vector<SeafEvent>& new_events);
+
+ GetEventsRequest *get_events_req_;
+
+ GetEventsRequestV2 *get_file_activities_req_;
+
+ std::vector<SeafEvent> events_;
+
+ bool in_refresh_;
+
+ // for old api, it's an offset
+ // for new api, it's the next page number
+ int next_;
+};
+
+
+#endif // SEAFILE_CLIENT_EVENTS_SERVICE_H
--- /dev/null
+#include <winsock2.h>
+#include <windows.h>
+#include <io.h>
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <userenv.h>
+
+#include <string>
+#include <QMutexLocker>
+#include <QScopedPointer>
+#include <QList>
+#include <QVector>
+#include <QDir>
+#include <QTimer>
+#include <QDateTime>
+#include <QDebug>
+
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/sharedlink-dialog.h"
+#include "filebrowser/seafilelink-dialog.h"
+#include "ui/private-share-dialog.h"
+#include "rpc/rpc-client.h"
+#include "repo-service.h"
+#include "api/api-error.h"
+#include "seafile-applet.h"
+#include "daemon-mgr.h"
+#include "account-mgr.h"
+#include "settings-mgr.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/utils-win.h"
+#include "auto-login-service.h"
+#include "ext-handler.h"
+
+namespace {
+
+const char *kSeafExtPipeName = "\\\\.\\pipe\\seafile_ext_pipe_";
+const int kPipeBufSize = 1024;
+
+const quint64 kReposInfoCacheMSecs = 2000;
+
+bool
+extPipeReadN (HANDLE pipe, void *buf, size_t len)
+{
+ DWORD bytes_read;
+ bool success = ReadFile(
+ pipe, // handle to pipe
+ buf, // buffer to receive data
+ (DWORD)len, // size of buffer
+ &bytes_read, // number of bytes read
+ NULL); // not overlapped I/O
+
+ if (!success || bytes_read != (DWORD)len) {
+ DWORD error = GetLastError();
+ if (error == ERROR_BROKEN_PIPE) {
+ qDebug("[ext] connection closed by extension\n");
+ } else {
+ qWarning("[ext] Failed to read command from extension(), "
+ "error code %lu\n", error);
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool
+extPipeWriteN(HANDLE pipe, void *buf, size_t len)
+{
+ DWORD bytes_written;
+ bool success = WriteFile(
+ pipe, // handle to pipe
+ buf, // buffer to receive data
+ (DWORD)len, // size of buffer
+ &bytes_written, // number of bytes written
+ NULL); // not overlapped I/O
+
+ if (!success || bytes_written != (DWORD)len) {
+ DWORD error = GetLastError();
+ if (error == ERROR_BROKEN_PIPE) {
+ qDebug("[ext] connection closed by extension\n");
+ } else {
+ qWarning("[ext] Failed to read command from extension(), "
+ "error code %lu\n", error);
+ }
+ return false;
+ }
+
+ FlushFileBuffers(pipe);
+ return true;
+}
+
+/**
+ * Replace "\" with "/", and remove the trailing slash
+ */
+QString normalizedPath(const QString& path)
+{
+ QString p = QDir::fromNativeSeparators(path);
+ if (p.endsWith("/")) {
+ p = p.left(p.size() - 1);
+ }
+ return p;
+}
+
+std::string formatErrorMessage()
+{
+ DWORD error_code = ::GetLastError();
+ if (error_code == 0) {
+ return "no error";
+ }
+ char buf[256] = {0};
+ ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ error_code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ buf,
+ sizeof(buf) - 1,
+ NULL);
+ return buf;
+}
+
+QString repoStatus(const LocalRepo& repo)
+{
+ QString status = "normal";
+ if (!repo.auto_sync) {
+ status = "paused";
+ } else if (repo.sync_state == LocalRepo::SYNC_STATE_ING) {
+ status = "syncing";
+ } else if (repo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+ status = "error";
+ }
+
+ // qDebug("repo %s (%s, %s): %s", repo.name.toUtf8().data(),
+ // repo.sync_state_str.toUtf8().data(),
+ // repo.sync_error_str.toUtf8().data(),
+ // status.toUtf8().data());
+
+ return status;
+}
+
+} // namespace
+
+
+SINGLETON_IMPL(SeafileExtensionHandler)
+
+SeafileExtensionHandler::SeafileExtensionHandler()
+: started_(false)
+{
+ listener_thread_ = new ExtConnectionListenerThread;
+
+ connect(listener_thread_, SIGNAL(generateShareLink(const QString&, const QString&, bool, bool)),
+ this, SLOT(generateShareLink(const QString&, const QString&, bool, bool)));
+
+ connect(listener_thread_, SIGNAL(lockFile(const QString&, const QString&, bool)),
+ this, SLOT(lockFile(const QString&, const QString&, bool)));
+
+ connect(listener_thread_, SIGNAL(privateShare(const QString&, const QString&, bool)),
+ this, SLOT(privateShare(const QString&, const QString&, bool)));
+
+ connect(listener_thread_, SIGNAL(openUrlWithAutoLogin(const QUrl&)),
+ this, SLOT(openUrlWithAutoLogin(const QUrl&)));
+
+ connect(listener_thread_, SIGNAL(showLockedBy(const QString&, const QString&)),
+ this, SLOT(showLockedBy(const QString&, const QString&)));
+
+ connect(listener_thread_, SIGNAL(getUploadLink(const QString&, const QString&)),
+ this, SLOT(getUploadLink(const QString&, const QString&)));
+}
+
+void SeafileExtensionHandler::start()
+{
+ listener_thread_->start();
+ ReposInfoCache::instance()->start();
+ started_ = true;
+}
+
+void SeafileExtensionHandler::stop()
+{
+ if (started_) {
+ // Before seafile client exits, tell the shell to clean all the file
+ // status icons
+ SHChangeNotify (SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+ }
+}
+
+void SeafileExtensionHandler::generateShareLink(const QString& repo_id,
+ const QString& path_in_repo,
+ bool is_file,
+ bool internal)
+{
+ // qDebug("path_in_repo: %s", path_in_repo.toUtf8().data());
+ const Account account = seafApplet->accountManager()->getAccountByRepo(repo_id);
+ if (!account.isValid()) {
+ return;
+ }
+
+ if (internal) {
+ QString path = path_in_repo;
+ if (!is_file && !path.endsWith("/")) {
+ path += "/";
+ }
+ GetSmartLinkRequest *req = new GetSmartLinkRequest(account, repo_id, path, !is_file);
+ connect(req, SIGNAL(success(const QString&, const QString&)),
+ this, SLOT(onGetSmartLinkSuccess(const QString&, const QString&)));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetSmartLinkFailed(const ApiError&)));
+
+ req->send();
+ } else {
+ GetSharedLinkRequest *req = new GetSharedLinkRequest(
+ account, repo_id, path_in_repo, is_file);
+
+ connect(req, SIGNAL(success(const QString&, const QString&)),
+ this, SLOT(onShareLinkGenerated(const QString&)));
+
+ req->send();
+ }
+}
+
+void SeafileExtensionHandler::onGetSmartLinkSuccess(const QString& smart_link, const QString& protocol_link)
+{
+ GetSmartLinkRequest *req = (GetSmartLinkRequest *)(sender());
+ SeafileLinkDialog *dialog = new SeafileLinkDialog(smart_link, protocol_link, NULL);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+ req->deleteLater();
+}
+
+void SeafileExtensionHandler::onGetSmartLinkFailed(const ApiError& error)
+{
+ seafApplet->warningBox(tr("Failed to get link"));
+}
+
+void SeafileExtensionHandler::lockFile(const QString& repo_id,
+ const QString& path_in_repo,
+ bool lock)
+{
+ // qDebug("path_in_repo: %s", path_in_repo.toUtf8().data());
+ const Account account = seafApplet->accountManager()->getAccountByRepo(repo_id);
+ if (!account.isValid()) {
+ return;
+ }
+
+ LockFileRequest *req = new LockFileRequest(
+ account, repo_id, path_in_repo, lock);
+
+ connect(req, SIGNAL(success(const QString&)),
+ this, SLOT(onLockFileSuccess()));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onLockFileFailed(const ApiError&)));
+
+ req->send();
+}
+
+void SeafileExtensionHandler::privateShare(const QString& repo_id,
+ const QString& path_in_repo,
+ bool to_group)
+{
+ const Account account = seafApplet->accountManager()->getAccountByRepo(repo_id);
+ if (!account.isValid()) {
+ qWarning("no account found for repo %12s", repo_id.toUtf8().data());
+ return;
+ }
+
+ LocalRepo repo;
+ seafApplet->rpcClient()->getLocalRepo(repo_id, &repo);
+ PrivateShareDialog *dialog = new PrivateShareDialog(account, repo_id, repo.name,
+ path_in_repo, to_group,
+ NULL);
+
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void SeafileExtensionHandler::openUrlWithAutoLogin(const QUrl& url)
+{
+ AutoLoginService::instance()->startAutoLogin(url.toString());
+}
+
+void SeafileExtensionHandler::onShareLinkGenerated(const QString& link)
+{
+ SharedLinkDialog *dialog = new SharedLinkDialog(link, NULL);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void SeafileExtensionHandler::onLockFileSuccess()
+{
+ LockFileRequest *req = qobject_cast<LockFileRequest *>(sender());
+ LocalRepo repo;
+ seafApplet->rpcClient()->getLocalRepo(req->repoId(), &repo);
+ if (repo.isValid()) {
+ seafApplet->rpcClient()->markFileLockState(req->repoId(), req->path(), req->lock());
+ QString path = QDir::toNativeSeparators(QDir(repo.worktree).absoluteFilePath(req->path().mid(1)));
+ SHChangeNotify(SHCNE_ATTRIBUTES, SHCNF_PATH, path.toUtf8().data(), NULL);
+ }
+}
+
+void SeafileExtensionHandler::onLockFileFailed(const ApiError& error)
+{
+ LockFileRequest *req = qobject_cast<LockFileRequest *>(sender());
+ QString str = req->lock() ? tr("Failed to lock file") : tr("Failed to unlock file");
+ seafApplet->warningBox(QString("%1: %2").arg(str, error.toString()));
+}
+
+void SeafileExtensionHandler::getUploadLink(const QString& repo_id, const QString& path_in_repo)
+{
+ const Account account =
+ seafApplet->accountManager()->getAccountByRepo(repo_id);
+ if (!account.isValid()) {
+ return;
+ }
+
+ GetUploadLinkRequest *req = new GetUploadLinkRequest(
+ account, repo_id, "/" + path_in_repo);
+ connect(req, SIGNAL(success(const QString&)), this,
+ SLOT(onGetUploadLinkSuccess(const QString)));
+ connect(req, SIGNAL(failed(const ApiError&)), this,
+ SLOT(onGetUploadLinkFailed(const ApiError&)));
+ req->send();
+
+}
+
+void SeafileExtensionHandler::onGetUploadLinkSuccess(const QString& upload_link)
+{
+ SharedLinkDialog *dialog = new SharedLinkDialog(upload_link, NULL, false);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void SeafileExtensionHandler::onGetUploadLinkFailed(const ApiError& error)
+{
+ GetUploadLinkRequest *req = qobject_cast<GetUploadLinkRequest *>(sender());
+ const QString file = ::getBaseName(req->path());
+ seafApplet->messageBox(tr("Failed to get upload link information for file \"%1\"").arg(file));
+ req->deleteLater();
+}
+
+void SeafileExtensionHandler::showLockedBy(const QString& repo_id, const QString& path_in_repo)
+{
+ // qWarning("SeafileExtensionHandler::showLockedBy is called for %s %s\n",
+ // toCStr(repo_id),
+ // toCStr(path_in_repo));
+ const Account account =
+ seafApplet->accountManager()->getAccountByRepo(repo_id);
+ if (!account.isValid()) {
+ return;
+ }
+
+ GetFileLockInfoRequest *req = new GetFileLockInfoRequest(
+ account, repo_id, QString("/").append(path_in_repo));
+
+ connect(req, SIGNAL(success(bool, const QString&)), this,
+ SLOT(onGetFileLockInfoSuccess(bool, const QString &)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetFileLockInfoFailed(const ApiError&)));
+
+ req->send();
+}
+
+void SeafileExtensionHandler::onGetFileLockInfoSuccess(bool found, const QString& lock_owner)
+{
+ // printf ("found: %s, lock_owner: %s\n", found ? "true" : "false", toCStr(lock_owner));
+ GetFileLockInfoRequest *req = qobject_cast<GetFileLockInfoRequest *>(sender());
+ const QString file = ::getBaseName(req->path());
+
+ if (found) {
+ seafApplet->messageBox(tr("File \"%1\" is locked by %2").arg(file, lock_owner));
+ } else {
+ seafApplet->messageBox(tr("Failed to get lock information for file \"%1\"").arg(file));
+ }
+ req->deleteLater();
+}
+
+void SeafileExtensionHandler::onGetFileLockInfoFailed(const ApiError& error)
+{
+ GetFileLockInfoRequest *req = qobject_cast<GetFileLockInfoRequest *>(sender());
+ const QString file = ::getBaseName(req->path());
+ seafApplet->messageBox(tr("Failed to get lock information for file \"%1\"").arg(file));
+ req->deleteLater();
+}
+
+
+
+void ExtConnectionListenerThread::run()
+{
+ std::string local_pipe_name = utils::win::getLocalPipeName(kSeafExtPipeName);
+ qWarning("[ext listener] listening on %s", local_pipe_name.c_str());
+ while (1) {
+ HANDLE pipe = INVALID_HANDLE_VALUE;
+ bool connected = false;
+
+ pipe = CreateNamedPipe(
+ local_pipe_name.c_str(), // pipe name
+ PIPE_ACCESS_DUPLEX, // read/write access
+ PIPE_TYPE_MESSAGE | // message type pipe
+ PIPE_READMODE_MESSAGE | // message-read mode
+ PIPE_WAIT, // blocking mode
+ PIPE_UNLIMITED_INSTANCES, // max. instances
+ kPipeBufSize, // output buffer size
+ kPipeBufSize, // input buffer size
+ 0, // client time-out
+ NULL); // default security attribute
+
+ if (pipe == INVALID_HANDLE_VALUE) {
+ qWarning ("Failed to create named pipe, GLE=%lu\n",
+ GetLastError());
+ return;
+ }
+
+ /* listening on this pipe */
+ connected = ConnectNamedPipe(pipe, NULL) ?
+ true : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+ if (!connected) {
+ qWarning ("Failed on ConnectNamedPipe(), GLE=%lu\n",
+ GetLastError());
+ CloseHandle(pipe);
+ return;
+ }
+
+ qDebug ("[ext pipe] Accepted an extension pipe client\n");
+ servePipeInNewThread(pipe);
+ }
+}
+
+void ExtConnectionListenerThread::servePipeInNewThread(HANDLE pipe)
+{
+ ExtCommandsHandler *t = new ExtCommandsHandler(pipe);
+
+ connect(t, SIGNAL(generateShareLink(const QString&, const QString&, bool, bool)),
+ this, SIGNAL(generateShareLink(const QString&, const QString&, bool, bool)));
+ connect(t, SIGNAL(lockFile(const QString&, const QString&, bool)),
+ this, SIGNAL(lockFile(const QString&, const QString&, bool)));
+ connect(t, SIGNAL(privateShare(const QString&, const QString&, bool)),
+ this, SIGNAL(privateShare(const QString&, const QString&, bool)));
+ connect(t, SIGNAL(openUrlWithAutoLogin(const QUrl&)),
+ this, SIGNAL(openUrlWithAutoLogin(const QUrl&)));
+ connect(t, SIGNAL(showLockedBy(const QString&, const QString&)),
+ this, SIGNAL(showLockedBy(const QString&, const QString&)));
+ connect(t, SIGNAL(getUploadLink(const QString&, const QString&)),
+ this, SIGNAL(getUploadLink(const QString&, const QString&)));
+ t->start();
+}
+
+ExtCommandsHandler::ExtCommandsHandler(HANDLE pipe)
+{
+ pipe_ = pipe;
+}
+
+void ExtCommandsHandler::run()
+{
+ while (1) {
+ QStringList args;
+ if (!readRequest(&args)) {
+ qWarning ("failed to read request from shell extension: %s",
+ formatErrorMessage().c_str());
+ break;
+ }
+
+ QString cmd = args.takeAt(0);
+ QString resp;
+ if (cmd == "list-repos") {
+ resp = handleListRepos(args);
+ } else if (cmd == "get-share-link") {
+ handleGenShareLink(args, false);
+ } else if (cmd == "get-internal-link") {
+ handleGenShareLink(args, true);
+ } else if (cmd == "get-file-status") {
+ resp = handleGetFileStatus(args);
+ } else if (cmd == "lock-file") {
+ handleLockFile(args, true);
+ } else if (cmd == "unlock-file") {
+ handleLockFile(args, false);
+ } else if (cmd == "private-share-to-group") {
+ handlePrivateShare(args, true);
+ } else if (cmd == "private-share-to-user") {
+ handlePrivateShare(args, false);
+ } else if (cmd == "show-history") {
+ handleShowHistory(args);
+ } else if (cmd == "show-locked-by") {
+ handleShowLockedBy(args);
+ } else if (cmd == "get-upload-link") {
+ handleGetUploadLink(args);
+ } else {
+ qWarning ("[ext] unknown request command: %s", cmd.toUtf8().data());
+ }
+
+ if (!sendResponse(resp)) {
+ qWarning ("failed to write response to shell extension: %s",
+ formatErrorMessage().c_str());
+ break;
+ }
+ }
+
+ qDebug ("An extension client is disconnected: GLE=%lu\n",
+ GetLastError());
+ DisconnectNamedPipe(pipe_);
+ CloseHandle(pipe_);
+}
+
+bool ExtCommandsHandler::readRequest(QStringList *args)
+{
+ uint32_t len = 0;
+ if (!extPipeReadN(pipe_, &len, sizeof(len)) || len == 0)
+ return false;
+
+ QScopedArrayPointer<char> buf(new char[len + 1]);
+ buf.data()[len] = 0;
+ if (!extPipeReadN(pipe_, buf.data(), len))
+ return false;
+
+ QStringList list = QString::fromUtf8(buf.data()).split('\t');
+ if (list.empty()) {
+ qWarning("[ext] got an empty request");
+ return false;
+ }
+ *args = list;
+ return true;
+}
+
+bool ExtCommandsHandler::sendResponse(const QString& resp)
+{
+ QByteArray raw_resp = resp.toUtf8();
+ uint32_t len = raw_resp.length();
+
+ if (!extPipeWriteN(pipe_, &len, sizeof(len))) {
+ return false;
+ }
+ if (len > 0) {
+ if (!extPipeWriteN(pipe_, raw_resp.data(), len)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+QList<LocalRepo> ExtCommandsHandler::listLocalRepos(quint64 ts)
+{
+ return ReposInfoCache::instance()->getReposInfo(ts);
+}
+
+void ExtCommandsHandler::handleGenShareLink(const QStringList& args, bool internal)
+{
+ if (args.size() != 1) {
+ return;
+ }
+ QString path = normalizedPath(args[0]);
+ foreach (const LocalRepo& repo, listLocalRepos()) {
+ QString wt = normalizedPath(repo.worktree);
+ // qDebug("path: %s, repo: %s", path.toUtf8().data(), wt.toUtf8().data());
+ if (path.length() > wt.length() && path.startsWith(wt) && path.at(wt.length()) == '/') {
+ QString path_in_repo = path.mid(wt.size());
+ bool is_file = QFileInfo(path).isFile();
+ emit generateShareLink(repo.id, path_in_repo, is_file, internal);
+ break;
+ }
+ }
+}
+
+QString ExtCommandsHandler::handleListRepos(const QStringList& args)
+{
+ if (args.size() < 1) {
+ return "";
+ }
+ bool ok;
+ quint64 ts = args[0].toULongLong(&ok);
+ if (!ok) {
+ return "";
+ }
+
+ // In older versions of the shell ext it sends one argument (the
+ // cache timestamp) and expects to see exactly six fields.
+ bool new_version = args.size() > 1;
+ QStringList infos;
+ // TODO: We should use json for the requests/responses between
+ // shell-ext <=> seafile client
+ foreach (const LocalRepo& repo, listLocalRepos(ts)) {
+ QStringList fields;
+ QString file_lock = repo.account.isAtLeastProVersion(4, 3, 0)
+ ? "file-lock-supported"
+ : "file-lock-unsupported";
+ QString private_share = "private-share-supported";
+ if (!repo.account.isPro()) {
+ private_share = "private-share-unsupported";
+ } else {
+ // TODO: Sometimes we can't get the repo info, e.g. when the
+ // account the repo belongs to is not the current active account.
+ ServerRepo server_repo = RepoService::instance()->getRepo(repo.id);
+ if (server_repo.isValid() && server_repo.owner != repo.account.username) {
+ private_share = "private-share-unsupported";
+ }
+ }
+ fields << repo.id
+ << repo.name
+ << normalizedPath(repo.worktree)
+ << repoStatus(repo)
+ << file_lock
+ << private_share;
+
+ if (new_version) {
+ QString internal_link_supported = repo.account.isAtLeastVersion(6, 3, 0)
+ ? "internal-link-supported"
+ : "internal-link-unsupported";
+
+ fields << internal_link_supported;
+ }
+ infos << fields.join("\t");
+ }
+
+ return infos.join("\n");
+}
+
+QString ExtCommandsHandler::handleGetFileStatus(const QStringList& args)
+{
+ if (args.size() != 3) {
+ return "";
+ }
+
+ QString repo_id = args[0];
+ QString path_in_repo = args[1];
+ bool isdir = args[2] == "true";
+ if (repo_id.length() != 36) {
+ return "";
+ }
+
+ QString status;
+ if (ReposInfoCache::instance()->getRepoFileStatus(repo_id, path_in_repo, isdir, &status)) {
+ // qWarning("status for %s is %s", path_in_repo.toUtf8().data(), status.toUtf8().data());
+ return status;
+ }
+
+ qWarning("failed to get file status for %s", path_in_repo.toUtf8().data());
+ return "";
+}
+
+void ExtCommandsHandler::handleLockFile(const QStringList& args, bool lock)
+{
+ if (args.size() != 1) {
+ return;
+ }
+ QString path = normalizedPath(args[0]);
+ foreach (const LocalRepo& repo, listLocalRepos()) {
+ QString wt = normalizedPath(repo.worktree);
+ if (path.length() > wt.length() && path.startsWith(wt) and path.at(wt.length()) == '/') {
+ QString path_in_repo = path.mid(wt.size());
+ emit lockFile(repo.id, path_in_repo, lock);
+ break;
+ }
+ }
+}
+
+void ExtCommandsHandler::handlePrivateShare(const QStringList& args,
+ bool to_group)
+{
+ if (args.size() != 1) {
+ return;
+ }
+ QString path = normalizedPath(args[0]);
+ if (!QFileInfo(path).isDir()) {
+ qWarning("attempted to share %s, which is not a folder",
+ path.toUtf8().data());
+ return;
+ }
+ foreach (const LocalRepo& repo, listLocalRepos()) {
+ QString wt = normalizedPath(repo.worktree);
+ if (path.length() > wt.length() && path.startsWith(wt) &&
+ path.at(wt.length()) == '/') {
+ QString path_in_repo = path.mid(wt.size());
+ emit privateShare(repo.id, path_in_repo, to_group);
+ break;
+ }
+ }
+}
+
+void ExtCommandsHandler::handleShowHistory(const QStringList& args)
+{
+ if (args.size() != 1) {
+ return;
+ }
+ QString path = normalizedPath(args[0]);
+ if (QFileInfo(path).isDir()) {
+ qWarning("attempted to view history of %s, which is not a regular file",
+ path.toUtf8().data());
+ return;
+ }
+ foreach (const LocalRepo& repo, listLocalRepos()) {
+ QString wt = normalizedPath(repo.worktree);
+ if (path.length() > wt.length() && path.startsWith(wt) &&
+ path.at(wt.length()) == '/') {
+ if (repo.account.isValid()) {
+ QString path_in_repo = path.mid(wt.size());
+ QUrl url = "/repo/file_revisions/" + repo.id + "/";
+ url = ::includeQueryParams(url, {{"p", path_in_repo}});
+ emit openUrlWithAutoLogin(url);
+ }
+ break;
+ }
+ }
+}
+
+
+void ExtCommandsHandler::handleShowLockedBy(const QStringList& args)
+{
+ if (args.size() != 1) {
+ return;
+ }
+ QString path = normalizedPath(args[0]);
+ foreach (const LocalRepo& repo, listLocalRepos()) {
+ QString wt = normalizedPath(repo.worktree);
+ // qDebug("path: %s, repo: %s", path.toUtf8().data(), wt.toUtf8().data());
+ if (path.length() > wt.length() && path.startsWith(wt) && path.at(wt.length()) == '/') {
+ QString path_in_repo = path.mid(wt.size());
+ emit showLockedBy(repo.id, path_in_repo);
+ break;
+ }
+ }
+}
+
+void ExtCommandsHandler::handleGetUploadLink(const QStringList& args)
+{
+ if (args.size() != 1) {
+ return;
+ }
+ QString path = normalizedPath(args[0]);
+ foreach (const LocalRepo& repo, listLocalRepos()) {
+ QString wt = normalizedPath(repo.worktree);
+ // qDebug("path: %s, repo: %s", path.toUtf8().data(), wt.toUtf8().data());
+ if (path.length() > wt.length() && path.startsWith(wt) && path.at(wt.length()) == '/') {
+ QString path_in_repo = path.mid(wt.size());
+ emit getUploadLink(repo.id, path_in_repo);
+ break;
+ }
+ }
+}
+
+SINGLETON_IMPL(ReposInfoCache)
+
+ReposInfoCache::ReposInfoCache(QObject * parent)
+ : QObject(parent)
+{
+ cache_ts_ = 0;
+ rpc_client_ = new SeafileRpcClient();
+ connect(seafApplet->daemonManager(), SIGNAL(daemonRestarted()), this, SLOT(onDaemonRestarted()));
+}
+
+void ReposInfoCache::start()
+{
+ rpc_client_->tryConnectDaemon();
+}
+
+void ReposInfoCache::onDaemonRestarted()
+{
+ QMutexLocker lock(&rpc_client_mutex_);
+ qDebug("reviving message poller when daemon is restarted");
+ if (rpc_client_) {
+ delete rpc_client_;
+ }
+ rpc_client_ = new SeafileRpcClient();
+ rpc_client_->tryConnectDaemon();
+}
+
+
+QList<LocalRepo> ReposInfoCache::getReposInfo(quint64 ts)
+{
+ QMutexLocker lock(&rpc_client_mutex_);
+
+ // There are two levels of repos lists cache in the shell extension:
+ // 1. The extension would cache the repos list in explorer side so it
+ // doesn't need to queries the applet repeatly in situations like
+ // entering a folder with lots of files
+ // 2. The applet would also cache the repos list (in ReposInfoCache), this
+ // is to reduce the overhead when different extension connections askes
+ // for the repos list simultaneously
+
+ quint64 now = QDateTime::currentMSecsSinceEpoch();
+
+ if (cache_ts_ != 0 && cache_ts_ > ts && now - cache_ts_ < kReposInfoCacheMSecs) {
+ // qDebug("ReposInfoCache: return cached info");
+ return cached_info_;
+ }
+ // qDebug("ReposInfoCache: fetch from daemon");
+
+ std::vector<LocalRepo> repos;
+ rpc_client_->listLocalRepos(&repos);
+
+ for (size_t i = 0; i < repos.size(); i++) {
+ LocalRepo& repo = repos[i];
+ rpc_client_->getSyncStatus(repo);
+ repo.account = seafApplet->accountManager()->getAccountByRepo(repo.id, rpc_client_);
+ }
+
+ cached_info_ = QVector<LocalRepo>::fromStdVector(repos).toList();
+ cache_ts_ = QDateTime::currentMSecsSinceEpoch();
+
+ return cached_info_;
+}
+
+bool ReposInfoCache::getRepoFileStatus(const QString& repo_id,
+ const QString& path_in_repo,
+ bool isdir,
+ QString *status)
+{
+ QMutexLocker lock(&rpc_client_mutex_);
+ return rpc_client_->getRepoFileStatus(repo_id, path_in_repo, isdir, status) == 0;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_EXT_HANLDER_H
+#define SEAFILE_CLIENT_EXT_HANLDER_H
+
+#include <QObject>
+#include <QThread>
+#include <QMutex>
+#include <QList>
+#include <QHash>
+
+#include <windows.h>
+
+#include "utils/singleton.h"
+#include "rpc/local-repo.h"
+#include "account.h"
+
+class SeafileRpcClient;
+class ExtConnectionListenerThread;
+class ApiError;
+
+/**
+ * Handles commands from seafile shell extension
+ */
+class SeafileExtensionHandler : public QObject {
+ SINGLETON_DEFINE(SeafileExtensionHandler)
+ Q_OBJECT
+
+public:
+ SeafileExtensionHandler();
+ void start();
+ void stop();
+
+private slots:
+ void onShareLinkGenerated(const QString& link);
+ void onLockFileSuccess();
+ void onLockFileFailed(const ApiError& error);
+ void generateShareLink(const QString& repo_id,
+ const QString& path_in_repo,
+ bool is_file,
+ bool internal);
+ void lockFile(const QString& repo_id,
+ const QString& path_in_repo,
+ bool lock);
+ void privateShare(const QString& repo_id,
+ const QString& path_in_repo,
+ bool to_group);
+ void openUrlWithAutoLogin(const QUrl& url);
+ void onGetSmartLinkSuccess(const QString& smart_link, const QString& protocol_link);
+ void onGetSmartLinkFailed(const ApiError& error);
+ void getUploadLink(const QString& repo, const QString& path_in_repo);
+ void onGetUploadLinkSuccess(const QString &upload_link);
+ void onGetUploadLinkFailed(const ApiError& error);
+ void showLockedBy(const QString& repo_id, const QString& path_in_repo);
+ void onGetFileLockInfoSuccess(bool found, const QString &owner);
+ void onGetFileLockInfoFailed(const ApiError& error);
+
+private:
+ ExtConnectionListenerThread *listener_thread_;
+
+ bool started_;
+};
+
+/**
+ * Creates the named pipe and listen for incoming connections in a separate
+ * thread.
+ *
+ * When a connection is accepted, create a new ExtCommandsHandler thread to
+ * serve it.
+ */
+class ExtConnectionListenerThread : public QThread {
+ Q_OBJECT
+public:
+ void run();
+
+signals:
+ void generateShareLink(const QString& repo_id,
+ const QString& path_in_repo,
+ bool is_file,
+ bool internal);
+ void lockFile(const QString& repo_id,
+ const QString& path_in_repo,
+ bool lock);
+ void privateShare(const QString& repo_id,
+ const QString& path_in_repo,
+ bool to_group);
+ void openUrlWithAutoLogin(const QUrl& url);
+ void showLockedBy(const QString& repo_id, const QString& path_in_repo);
+ void getUploadLink(const QString& repo_id, const QString& path_in_repo);
+
+private:
+ void servePipeInNewThread(HANDLE pipe);
+};
+
+/**
+ * Serves one extension connection.
+ *
+ * It's an endless loop of "read request" -> "handle request" -> "send response".
+ */
+class ExtCommandsHandler: public QThread {
+ Q_OBJECT
+public:
+ ExtCommandsHandler(HANDLE pipe);
+ void run();
+
+signals:
+ void generateShareLink(const QString& repo_id,
+ const QString& path_in_repo,
+ bool is_file,
+ bool internal);
+ void lockFile(const QString& repo_id,
+ const QString& path_in_repo,
+ bool lock);
+ void privateShare(const QString& repo_id,
+ const QString& path_in_repo,
+ bool to_group);
+ void openUrlWithAutoLogin(const QUrl& url);
+ void showLockedBy(const QString& repo_id, const QString& path_in_repo);
+ void getUploadLink(const QString& repo_id, const QString& path_in_repo);
+
+private:
+ HANDLE pipe_;
+
+ QList<LocalRepo> listLocalRepos(quint64 ts = 0);
+ bool readRequest(QStringList *args);
+ bool sendResponse(const QString& resp);
+
+ void handleGenShareLink(const QStringList& args, bool internal);
+ QString handleListRepos(const QStringList& args);
+ QString handleGetFileStatus(const QStringList& args);
+ void handleLockFile(const QStringList& args, bool lock);
+ void handlePrivateShare(const QStringList& args, bool to_group);
+ void handleShowHistory(const QStringList& args);
+ void handleShowLockedBy(const QStringList& args);
+ void handleGetUploadLink(const QStringList& args);
+};
+
+class ReposInfoCache : public QObject {
+ SINGLETON_DEFINE(ReposInfoCache)
+ Q_OBJECT
+public:
+ ReposInfoCache(QObject *parent=0);
+ void start();
+
+ QList<LocalRepo> getReposInfo(quint64 timestamp = 0);
+
+ bool getRepoFileStatus(const QString& repo_id,
+ const QString& path_in_repo,
+ bool isdir,
+ QString *status);
+
+private slots:
+ void onDaemonRestarted();
+
+private:
+ quint64 cache_ts_;
+ QList<LocalRepo> cached_info_;
+
+ SeafileRpcClient *rpc_client_;
+ QMutex rpc_client_mutex_;
+};
+
+#endif // SEAFILE_CLIENT_EXT_HANLDER_H
--- /dev/null
+#include <QApplication>
+#include <QDir>
+#include <QFileInfo>
+#include <QDateTime>
+#include <QTimer>
+#include <QThreadPool>
+
+#include "seafile-applet.h"
+#include "ui/tray-icon.h"
+#include "configurator.h"
+#include "account-mgr.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "utils/uninstall-helpers.h"
+#include "data-mgr.h"
+#include "tasks.h"
+#include "transfer-mgr.h"
+
+#include "auto-update-mgr.h"
+#include "repo-service.h"
+
+namespace {
+
+const char *kFileCacheTopDirName = "file-cache";
+const char *kFileCacheTempTopDirName = "file-cache-tmp";
+
+inline bool addPath(QFileSystemWatcher *watcher, const QString &file) {
+ if (watcher->files().contains(file))
+ return true;
+ bool ret = watcher->addPath(file);
+ if (!ret) {
+ qWarning("[AutoUpdateManager] failed to watch cache file %s", file.toUtf8().data());
+ }
+ return ret;
+}
+
+inline bool removePath(QFileSystemWatcher *watcher, const QString &file) {
+ if (!watcher->files().contains(file))
+ return true;
+ bool ret = watcher->removePath(file);
+ if (!ret) {
+ qWarning("[AutoUpdateManager] failed to remove watch on cache file %s", file.toUtf8().data());
+ }
+ return ret;
+}
+} // anonymous namespace
+
+SINGLETON_IMPL(AutoUpdateManager)
+
+
+AutoUpdateManager::AutoUpdateManager()
+{
+ system_shut_down_ = false;
+ connect(&watcher_, SIGNAL(fileChanged(const QString&)),
+ this, SLOT(onFileChanged(const QString&)));
+ connect(qApp, SIGNAL(aboutToQuit()),
+ this, SLOT(systemShutDown()));
+}
+
+void AutoUpdateManager::systemShutDown()
+{
+ system_shut_down_ = true;
+}
+
+void AutoUpdateManager::start()
+{
+ cleanCachedFile();
+}
+
+void AutoUpdateManager::watchCachedFile(const Account& account,
+ const QString& repo_id,
+ const QString& path)
+{
+ QString local_path = DataManager::getLocalCacheFilePath(repo_id, path);
+ qDebug("[AutoUpdateManager] watch cache file %s", local_path.toUtf8().data());
+ if (!QFileInfo(local_path).exists()) {
+ qWarning("[AutoUpdateManager] unable to watch non-existent cache file %s", local_path.toUtf8().data());
+ return;
+ }
+
+ // do we have it in deferred list ?
+ // skip if yes
+ Q_FOREACH(const WatchedFileInfo& info, deleted_files_infos_)
+ {
+ if (repo_id == info.repo_id && path == info.path_in_repo)
+ return;
+ }
+ Q_FOREACH(const WatchedFileInfo& info, watch_infos_)
+ {
+ if (repo_id == info.repo_id && path == info.path_in_repo)
+ return;
+ }
+
+ addPath(&watcher_, local_path);
+
+ QFileInfo finfo(local_path);
+ watch_infos_[local_path] =
+ WatchedFileInfo(account,
+ repo_id,
+ path,
+ finfo.lastModified().toMSecsSinceEpoch(),
+ finfo.size());
+}
+
+void AutoUpdateManager::cleanCachedFile()
+{
+ qWarning("[AutoUpdateManager] cancel all download tasks");
+ TransferManager::instance()->cancelAllDownloadTasks();
+
+ const Account cur_account = seafApplet->accountManager()->currentAccount();
+ foreach(const QString& key, watch_infos_.keys()) {
+ if (watch_infos_[key].account == cur_account)
+ watch_infos_.remove(key);
+ }
+
+ qWarning("[AutoUpdateManager] clean file caches db");
+ RepoService::instance()->removeCloudFileBrowserCache();
+
+ qWarning("[AutoUpdateManager] clean file caches");
+ CachedFilesCleaner *cleaner = new CachedFilesCleaner();
+ QThreadPool::globalInstance()->start(cleaner);
+}
+
+void AutoUpdateManager::uploadFile(const QString& local_path)
+{
+ qDebug("start upload file %s", toCStr(local_path));
+ WatchedFileInfo &info = watch_infos_[local_path];
+
+ FileNetworkTask *task = seafApplet->dataManager()->createUploadTask(
+ info.repo_id, ::getParentPath(info.path_in_repo),
+ local_path, ::getBaseName(local_path), true);
+
+ ((FileUploadTask *)task)->setAcceptUserConfirmation(false);
+
+ connect(task, SIGNAL(finished(bool)),
+ this, SLOT(onUpdateTaskFinished(bool)));
+
+ qDebug("[AutoUpdateManager] start uploading new version of file %s", local_path.toUtf8().data());
+
+ info.uploading = true;
+
+ task->start();
+}
+
+void AutoUpdateManager::onFileChanged(const QString& local_path)
+{
+ qDebug("[AutoUpdateManager] detected cache file %s changed", local_path.toUtf8().data());
+ if (!watch_infos_.contains(local_path)) {
+ // filter unwanted events
+ return;
+ }
+
+ WatchedFileInfo &info = watch_infos_[local_path];
+ QFileInfo finfo(local_path);
+
+ // Download the doc file in the mac will automatically upload
+ // If the timestamp has not changed, it will not be uploaded
+ qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+ if (mtime == info.mtime) {
+ qDebug("[AutoUpdateManager] Received a file %s upload notification, but the timestamp has not changed, "
+ "it will not upload", local_path.toUtf8().data());
+ return;
+ }
+
+#ifdef Q_OS_MAC
+ if (MacImageFilesWorkAround::instance()->isRecentOpenedImage(local_path)) {
+ qDebug("[AutoUpdateManager] skip the image file updates on mac for %s", toCStr(local_path));
+ return;
+ }
+#endif
+ removePath(&watcher_, local_path);
+ QString repo_id, path_in_repo;
+
+ if (!finfo.exists()) {
+ qDebug("[AutoUpdateManager] detected cache file %s renamed or removed", local_path.toUtf8().data());
+ WatchedFileInfo deferred_info = info;
+ removeWatch(local_path);
+ // Some application would deleted and recreate the file when saving.
+ // We work around that by double checking whether the file gets
+ // recreated after a short period
+ QTimer::singleShot(5000, this, SLOT(checkFileRecreated()));
+ deleted_files_infos_.enqueue(deferred_info);
+ return;
+ }
+
+ uploadFile(local_path);
+}
+
+void AutoUpdateManager::onUpdateTaskFinished(bool success)
+{
+ qDebug("on update task finished: %s", success ? "true" : "false");
+ if (system_shut_down_) {
+ return;
+ }
+
+ FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+ if (task == NULL)
+ return;
+ const QString local_path = task->localFilePath();
+ const QFileInfo finfo = QFileInfo(local_path);
+ if (!finfo.exists()) {
+ //TODO: What if the delete&recreate happens just before this function is called?
+ qWarning("[AutoUpdateManager] file %s not exists anymore", toCStr(local_path));
+ return;
+ }
+
+ if (!watch_infos_.contains(local_path)) {
+ qWarning("[AutoUpdateManager] no watch info for file %s", toCStr(local_path));
+ return;
+ }
+ WatchedFileInfo& info = watch_infos_[local_path];
+ info.uploading = false;
+
+ if (success) {
+ qDebug("[AutoUpdateManager] uploaded new version of file %s", local_path.toUtf8().data());
+ info.mtime = finfo.lastModified().toMSecsSinceEpoch();
+ info.fsize = finfo.size();
+ seafApplet->trayIcon()->showMessage(tr("Upload Success"),
+ tr("File \"%1\"\nuploaded successfully.").arg(finfo.fileName()),
+ task->repoId());
+
+ // This would also set the "uploading" and "num_upload_errors" column to 0.
+ FileCache::instance()->saveCachedFileId(task->repoId(),
+ info.path_in_repo,
+ task->account().getSignature(),
+ task->oid(),
+ task->localFilePath());
+ emit fileUpdated(task->repoId(), task->path());
+ } else {
+ qWarning("[AutoUpdateManager] failed to upload new version of file %s: %s",
+ toCStr(local_path),
+ toCStr(task->errorString()));
+ QString error_msg;
+ if (task->httpErrorCode() == 403) {
+ error_msg = tr("Permission Error!");
+ } else if (task->httpErrorCode() == 401) {
+ error_msg = tr("Authorization expired");
+ } else if (task->httpErrorCode() == 441) {
+ error_msg = tr("File does not exist");
+ } else {
+ error_msg = task->errorString();
+ }
+
+ QString name = ::getBaseName(local_path);
+ DirentsCache::ReturnEntry retval = DirentsCache::instance()->getCachedDirents(info.repo_id, task->path());
+ QList<SeafDirent> *l = retval.second;
+ QString msg = tr("File \"%1\"\nfailed to upload.").arg(QFileInfo(local_path).fileName());
+ if (l != NULL) {
+ foreach (const SeafDirent dirent, *l) {
+ if (dirent.name == name) {
+ if (dirent.is_locked) {
+ msg = tr("The file is locked by %1, "
+ "please try again later").arg(dirent.getLockOwnerDisplayString());
+ }
+ }
+ }
+ }
+ seafApplet->trayIcon()->showMessage(tr("Upload Failure: %1").arg(error_msg),
+ msg,
+ task->repoId());
+ }
+
+ addPath(&watcher_, local_path);
+}
+
+void AutoUpdateManager::removeWatch(const QString& local_path)
+{
+ watch_infos_.remove(local_path);
+ removePath(&watcher_, local_path);
+}
+
+void AutoUpdateManager::checkFileRecreated()
+{
+ if (deleted_files_infos_.isEmpty()) {
+ // impossible
+ return;
+ }
+
+ const WatchedFileInfo info = deleted_files_infos_.dequeue();
+ const QString path = DataManager::getLocalCacheFilePath(info.repo_id, info.path_in_repo);
+ if (QFileInfo(path).exists()) {
+ qDebug("[AutoUpdateManager] detected recreated file %s", path.toUtf8().data());
+ addPath(&watcher_, path);
+ watch_infos_[path] = info;
+ // Some applications like MSOffice would remove the original file and
+ // recreate it when the user modifies the file.
+ onFileChanged(path);
+ }
+}
+
+QHash<QString, AutoUpdateManager::FileStatus>
+AutoUpdateManager::getFileStatusForDirectory(const QString &account_sig,
+ const QString &repo_id,
+ const QString &parent_dir,
+ const QList<SeafDirent>& dirents)
+{
+ QHash<QString, SeafDirent> dirents_map;
+ foreach(const SeafDirent& d, dirents) {
+ if (d.isFile()) {
+ dirents_map[d.name] = d;
+ }
+ }
+
+ QHash<QString, FileStatus> ret;
+ QList<FileCache::CacheEntry> caches =
+ FileCache::instance()->getCachedFilesForDirectory(account_sig, repo_id, parent_dir);
+ if (caches.empty()) {
+ // qDebug("no cached files for dir %s\n", toCStr(parent_dir));
+ }
+ foreach(const FileCache::CacheEntry& entry, caches) {
+ // qDebug("found cache entry: %s\n", entry.path.toUtf8().data());
+
+ QString local_file_path = DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+ const QString& file = ::getBaseName(entry.path);
+ bool is_uploading = watch_infos_.contains(local_file_path) && watch_infos_[local_file_path].uploading;
+
+ if (!dirents_map.contains(file)) {
+ // qDebug("cached files no longer exists: %s\n", entry.path.toUtf8().data());
+ continue;
+ }
+
+ const SeafDirent& d = dirents_map[file];
+ if (d.id != entry.file_id) {
+ // qDebug("cached file is a stale version: %s\n", entry.path.toUtf8().data());
+ ret[file] = is_uploading ? UPLOADING : NOT_SYNCED;
+ continue;
+ }
+
+ QFileInfo finfo(local_file_path);
+
+ qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+ bool consistent = mtime == entry.seafile_mtime && finfo.size() == entry.seafile_size;
+ if (consistent) {
+ ret[file] = is_uploading ? UPLOADING: SYNCED;
+ } else {
+ ret[file] = is_uploading ? UPLOADING : NOT_SYNCED;
+ }
+ qDebug("is_uploading %s, local_file_path is %s", is_uploading ? "true" : "false", toCStr(local_file_path));
+ }
+ return ret;
+}
+
+#ifdef Q_OS_MAC
+SINGLETON_IMPL(MacImageFilesWorkAround)
+
+MacImageFilesWorkAround::MacImageFilesWorkAround()
+{
+}
+
+void MacImageFilesWorkAround::fileOpened(const QString& path)
+{
+ QString mimetype = ::mimeTypeFromFileName(path);
+ if (mimetype.startsWith("image") || mimetype == "application/pdf") {
+ images_[path] = QDateTime::currentMSecsSinceEpoch();
+ }
+}
+
+bool MacImageFilesWorkAround::isRecentOpenedImage(const QString& path)
+{
+ qint64 ts = images_.value(path, 0);
+ if (QDateTime::currentMSecsSinceEpoch() < ts + 1000 * 10) {
+ return true;
+ } else {
+ return false;
+ }
+}
+#endif
+
+CachedFilesCleaner::CachedFilesCleaner()
+{
+}
+
+void CachedFilesCleaner::run()
+{
+ QString file_cache_dir = pathJoin(seafApplet->configurator()->seafileDir(),
+ kFileCacheTopDirName);
+ QString file_cache_tmp_dir = pathJoin(seafApplet->configurator()->seafileDir(),
+ kFileCacheTempTopDirName);
+
+ qDebug("[AutoUpdateManager] removing cached files");
+ if (QDir(file_cache_tmp_dir).exists()) {
+ delete_dir_recursively(file_cache_tmp_dir);
+ }
+ if (QDir(file_cache_dir).exists()) {
+ // Delete the temporary directory in the old client.
+ if (QDir(file_cache_tmp_dir).exists()) {
+ delete_dir_recursively(file_cache_tmp_dir);
+ }
+ }
+}
+
+void AutoUpdateManager::dumpCacheStatus()
+{
+ printf ("---------------BEGIN CACHE INFO -------------\n");
+ foreach(const QString& key, watch_infos_.keys()) {
+ WatchedFileInfo& info = watch_infos_[key];
+ printf ("%s mtime = %lld, fsize = %lld, uploading = %s\n", toCStr(info.path_in_repo), info.mtime, info.fsize, info.uploading ? "true" : "false");
+ }
+ printf ("---------------END CACHE INFO -------------\n");
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_AUTO_UPDATE_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_AUTO_UPDATE_MANAGER_H
+
+#include <QFileSystemWatcher>
+#include <QHash>
+#include <QQueue>
+#include <QRunnable>
+#include <QScopedPointer>
+
+#include "utils/singleton.h"
+#include "account.h"
+#include "data-cache.h"
+#include "data-mgr.h"
+
+class AutoUpdateManager : public QObject {
+ SINGLETON_DEFINE(AutoUpdateManager)
+ Q_OBJECT
+
+public:
+ void start();
+ void removeWatch(const QString& path);
+ void watchCachedFile(const Account& account,
+ const QString& repo_id,
+ const QString& path);
+
+ enum FileStatus {
+ // Local cache is consistent with the version on the server
+ SYNCED = 0,
+ // The file is being auto-uploaded
+ UPLOADING,
+ // Not synced and also not uploading, this happens e.g. when the upload
+ // request failed
+ NOT_SYNCED,
+ };
+
+ QHash<QString, FileStatus> getFileStatusForDirectory(
+ const QString &account_sig,
+ const QString &repo_id,
+ const QString &path,
+ const QList<SeafDirent>& dirents);
+ void cleanCachedFile();
+ void uploadFile(const QString& local_path);
+ void dumpCacheStatus();
+
+signals:
+ void fileUpdated(const QString& repo_id, const QString& path);
+
+private slots:
+ void onFileChanged(const QString& path);
+ void onUpdateTaskFinished(bool success);
+ void checkFileRecreated();
+ void systemShutDown();
+
+private:
+ AutoUpdateManager();
+
+ QFileSystemWatcher watcher_;
+
+ struct WatchedFileInfo {
+ Account account;
+ QString repo_id;
+ QString path_in_repo;
+ qint64 mtime;
+ qint64 fsize;
+
+ bool uploading = false;
+
+ WatchedFileInfo() {}
+ WatchedFileInfo(const Account& account,
+ const QString& repo_id,
+ const QString& path_in_repo,
+ qint64 mtime,
+ qint64 fsize)
+ : account(account),
+ repo_id(repo_id),
+ path_in_repo(path_in_repo),
+ mtime(mtime),
+ fsize(fsize)
+ {}
+ };
+
+ QHash<QString, WatchedFileInfo> watch_infos_;
+
+ QQueue<WatchedFileInfo> deleted_files_infos_;
+
+ bool system_shut_down_;
+};
+
+#ifdef Q_OS_MAC
+/**
+ * On MacOSX, when open an image file in Preview app, a file modificatin event
+ * would be triggered, but the file is not modified. We need to work around
+ * this so the auto update manager would not be fooled by this false signal.
+ */
+class MacImageFilesWorkAround {
+ SINGLETON_DEFINE(MacImageFilesWorkAround)
+public:
+ MacImageFilesWorkAround();
+ bool isRecentOpenedImage(const QString& path);
+ void fileOpened(const QString& path);
+
+private:
+ QHash<QString, qint64> images_;
+};
+#endif // Q_OS_MAC
+
+class CachedFilesCleaner : public QObject, public QRunnable {
+ Q_OBJECT
+public:
+ CachedFilesCleaner();
+ void run();
+ bool autoDelete() {
+ return true;
+ }
+};
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_AUTO_UPDATE_MANAGER_H
--- /dev/null
+#include <QDir>
+#include <sqlite3.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <QDateTime>
+#include <QCache>
+
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "data-cache.h"
+#include "data-mgr.h"
+#include "account-mgr.h"
+
+namespace {
+
+const int kDirentsCacheExpireTime = 60 * 1000;
+
+void filecache_entry_from_sqlite3_result(sqlite3_stmt *stmt, FileCache::CacheEntry* entry)
+{
+ entry->repo_id = (const char *)sqlite3_column_text (stmt, 0);
+ entry->path = QString::fromUtf8((const char *)sqlite3_column_text (stmt, 1));
+ entry->account_sig = (const char *)sqlite3_column_text (stmt, 2);
+ entry->file_id = (const char *)sqlite3_column_text (stmt, 3);
+ entry->seafile_mtime = sqlite3_column_int64 (stmt, 4);
+ entry->seafile_size = sqlite3_column_int64 (stmt, 5);
+}
+
+} // namespace
+
+SINGLETON_IMPL(DirentsCache)
+DirentsCache::DirentsCache()
+{
+ cache_ = new QCache<QString, CacheEntry>;
+}
+DirentsCache::~DirentsCache()
+{
+ delete cache_;
+}
+
+DirentsCache::ReturnEntry
+DirentsCache::getCachedDirents(const QString& repo_id,
+ const QString& path)
+{
+ QString cache_key = repo_id + path;
+ CacheEntry *e = cache_->object(cache_key);
+ if (e != NULL) {
+ qint64 now = QDateTime::currentMSecsSinceEpoch();
+ if (now < e->timestamp + kDirentsCacheExpireTime) {
+ return ReturnEntry(e->current_readonly, &(e->dirents));
+ }
+ }
+
+ return ReturnEntry(false, NULL);
+}
+
+void DirentsCache::expireCachedDirents(const QString& repo_id, const QString& path)
+{
+ cache_->remove(repo_id + path);
+}
+
+void DirentsCache::saveCachedDirents(const QString& repo_id,
+ const QString& path,
+ bool current_readonly,
+ const QList<SeafDirent>& dirents)
+{
+ CacheEntry *val = new CacheEntry;
+ val->timestamp = QDateTime::currentMSecsSinceEpoch();
+ val->current_readonly = current_readonly;
+ val->dirents = dirents;
+ QString cache_key = repo_id + path;
+ cache_->insert(cache_key, val);
+}
+
+#if 0
+SINGLETON_IMPL(FileCache)
+FileCache::FileCache()
+{
+ cache_ = new QHash<QString, CacheEntry>;
+}
+
+FileCache::~FileCache()
+{
+ delete cache_;
+}
+
+QString FileCache::getCachedFileId(const QString& repo_id,
+ const QString& path)
+{
+ return getCacheEntry(repo_id, path).file_id;
+}
+
+FileCache::CacheEntry FileCache::getCacheEntry(const QString& repo_id,
+ const QString& path)
+{
+ QString cache_key = repo_id + path;
+
+ return cache_->value(cache_key);
+}
+
+void FileCache::saveCachedFileId(const QString& repo_id,
+ const QString& path,
+ const QString& file_id,
+ const QString& account_sig)
+{
+ CacheEntry val;
+ QString cache_key = repo_id + path;
+
+ val.repo_id = repo_id;
+ val.path = path;
+ val.file_id = file_id;
+ val.account_sig = account_sig;
+
+ cache_->insert(cache_key, val);
+}
+
+QList<FileCache::CacheEntry> FileCache::getAllCachedFiles()
+{
+ return cache_->values();
+}
+
+void FileCache::cleanCurrentAccountCache()
+{
+ const Account cur_account = seafApplet->accountManager()->currentAccount();
+ foreach(const QString& key, cache_->keys()) {
+ const Account account = seafApplet->accountManager()
+ ->getAccountBySignature(cache_->value(key).account_sig);
+ if (account == cur_account)
+ cache_->remove(key);
+ }
+}
+#endif
+
+SINGLETON_IMPL(FileCache)
+FileCache::FileCache()
+{
+ db_ = NULL;
+}
+
+FileCache::~FileCache()
+{
+ if (db_ != NULL)
+ sqlite3_close(db_);
+}
+
+void FileCache::start()
+{
+ const char *errmsg;
+ const char *sql;
+ sqlite3 *db;
+
+ QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("autoupdate-cache.db");
+ if (sqlite3_open (toCStr(db_path), &db)) {
+ errmsg = sqlite3_errmsg (db);
+ qDebug("failed to open file cache database %s: %s",
+ toCStr(db_path), errmsg ? errmsg : "no error given");
+
+ seafApplet->errorAndExit(QObject::tr("failed to open file cache database"));
+ return;
+ }
+
+ // Drop the old table.
+ // XX(lins05): This is not ideal. Should we invent a table schema upgrade mechanism?
+ sql = "DROP TABLE IF EXISTS FileCache;";
+ sqlite_query_exec (db, sql);
+ sql = "DROP TABLE IF EXISTS FileCacheV1;";
+ sqlite_query_exec (db, sql);
+
+ sql = "CREATE TABLE IF NOT EXISTS FileCacheV2 ("
+ " repo_id VARCHAR(36), "
+ " path VARCHAR(4096), "
+ " account_sig VARCHAR(40) NOT NULL, "
+ " file_id VARCHAR(40) NOT NULL, "
+ " seafile_mtime integer NOT NULL, "
+ " seafile_size integer NOT NULL, "
+ " PRIMARY KEY (repo_id, path))";
+ sqlite_query_exec (db, sql);
+
+ db_ = db;
+}
+
+bool FileCache::getCacheEntryCB(sqlite3_stmt *stmt, void *data)
+{
+ CacheEntry *entry = (CacheEntry *)data;
+ filecache_entry_from_sqlite3_result(stmt, entry);
+ return true;
+}
+
+bool FileCache::getCacheEntry(const QString& repo_id,
+ const QString& path,
+ FileCache::CacheEntry *entry)
+{
+ char *zql = sqlite3_mprintf("SELECT *"
+ " FROM FileCacheV2"
+ " WHERE repo_id = %Q"
+ " AND path = %Q",
+ repo_id.toUtf8().data(), path.toUtf8().data());
+ bool ret = sqlite_foreach_selected_row(db_, zql, getCacheEntryCB, entry) > 0;
+ sqlite3_free(zql);
+ return ret;
+}
+
+void FileCache::saveCachedFileId(const QString& repo_id,
+ const QString& path,
+ const QString& account_sig,
+ const QString& file_id,
+ const QString& local_file_path)
+{
+ QFileInfo finfo (local_file_path);
+ qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+ qint64 fsize = finfo.size();
+ char *zql = sqlite3_mprintf("REPLACE INTO FileCacheV2( "
+ "repo_id, path, account_sig, file_id, "
+ "seafile_mtime, seafile_size "
+ ") VALUES (%Q, %Q, %Q, %Q, %lld, %lld)",
+ toCStr(repo_id),
+ toCStr(path),
+ toCStr(account_sig),
+ toCStr(file_id),
+ mtime,
+ fsize);
+ sqlite_query_exec(db_, zql);
+ sqlite3_free(zql);
+}
+
+bool FileCache::collectCachedFile(sqlite3_stmt *stmt, void *data)
+{
+ QList<CacheEntry> *list = (QList<CacheEntry> *)data;
+
+ CacheEntry entry;
+ filecache_entry_from_sqlite3_result(stmt, &entry);
+ list->append(entry);
+ return true;
+}
+
+QList<FileCache::CacheEntry> FileCache::getAllCachedFiles()
+{
+ const char* sql = "SELECT * FROM FileCacheV2";
+ QList<CacheEntry> list;
+ sqlite_foreach_selected_row(db_, sql, collectCachedFile, &list);
+ return list;
+}
+
+void FileCache::cleanUnModifiedCacheItemInDatabase(const QString file_id) {
+ char* sql = sqlite3_mprintf("DELETE FROM FileCacheV2 WHERE file_id = %Q", toCStr(file_id));
+ sqlite_query_exec(db_, sql);
+ sqlite3_free(sql);
+}
+
+QList<FileCache::CacheEntry> FileCache::getCachedFilesForDirectory(const QString& account_sig,
+ const QString& repo_id,
+ const QString& parent_dir_in)
+{
+ QString parent_dir = parent_dir_in;
+ // Strip the trailing slash
+ if (parent_dir.length() > 1 && parent_dir.endsWith("/")) {
+ parent_dir = parent_dir.left(parent_dir.length() - 1);
+ }
+
+ QList<CacheEntry> entries;
+ char* sql = sqlite3_mprintf("SELECT * FROM FileCacheV2 "
+ "WHERE repo_id = %Q "
+ " AND path like %Q "
+ " AND account_sig = %Q; ",
+ toCStr(repo_id),
+ toCStr(QString("%1%").arg(parent_dir == "/" ? parent_dir : parent_dir + "/")),
+ toCStr(account_sig));
+
+ sqlite_foreach_selected_row(db_, sql, collectCachedFile, &entries);
+
+ // Even if we filtered the path in the above sql query, the returned entries
+ // may still belong to subdirectory of "parent_dir" instead of parent_dir
+ // itself. So we need to fitler again.
+ QList<CacheEntry> ret;
+ foreach(const CacheEntry& entry, entries) {
+ if (::getParentPath(entry.path) == parent_dir) {
+ QString localpath = DataManager::instance()->getLocalCacheFilePath(entry.repo_id, entry.path);
+ if (QFileInfo(localpath).exists()) {
+ ret.append(entry);
+ }
+ }
+ }
+ return ret;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_DATA_CACHE_H
+#define SEAFILE_CLIENT_FILE_BROWSER_DATA_CACHE_H
+
+#include <QList>
+#include <utility>
+
+#include "seaf-dirent.h"
+#include "utils/singleton.h"
+
+template<typename Key, typename T> class QCache;
+
+struct sqlite3;
+struct sqlite3_stmt;
+
+/**
+ * Cache dirents by (repo_id + path, dirents) in memory
+ */
+class DirentsCache {
+ SINGLETON_DEFINE(DirentsCache)
+public:
+ typedef std::pair<bool ,QList<SeafDirent>*> ReturnEntry;
+ ReturnEntry getCachedDirents(const QString& repo_id,
+ const QString& path);
+
+ void expireCachedDirents(const QString& repo_id, const QString& path);
+
+ void saveCachedDirents(const QString& repo_id,
+ const QString& path,
+ bool current_readonly,
+ const QList<SeafDirent>& dirents);
+
+private:
+ DirentsCache();
+ ~DirentsCache();
+ struct CacheEntry {
+ qint64 timestamp;
+ bool current_readonly;
+ QList<SeafDirent> dirents;
+ };
+
+ QCache<QString, CacheEntry> *cache_;
+};
+
+#if 0
+/**
+ * Record the file id of downloaded files.
+ * The schema is (repo_id, path, downloaded_file_id)
+ */
+class FileCache {
+ SINGLETON_DEFINE(FileCache)
+public:
+ struct CacheEntry {
+ QString repo_id;
+ QString path;
+ QString file_id;
+ QString account_sig;
+ };
+
+
+ QString getCachedFileId(const QString& repo_id,
+ const QString& path);
+ CacheEntry getCacheEntry(const QString& repo_id,
+ const QString& path);
+ void saveCachedFileId(const QString& repo_id,
+ const QString& path,
+ const QString& file_id,
+ const QString& account_sig);
+
+ QList<CacheEntry> getAllCachedFiles();
+ void cleanCurrentAccountCache();
+
+private:
+ FileCache();
+ ~FileCache();
+
+ QHash<QString, CacheEntry> *cache_;
+};
+#endif
+
+/**
+ * Record the file id of downloaded files.
+ */
+class FileCache {
+ SINGLETON_DEFINE(FileCache)
+public:
+ struct CacheEntry {
+ QString repo_id;
+ QString path;
+ QString account_sig;
+ QString file_id;
+ qint64 seafile_mtime;
+ qint64 seafile_size;
+ };
+
+ void start();
+
+ bool getCacheEntry(const QString& repo_id,
+ const QString& path,
+ CacheEntry *entry);
+ void saveCachedFileId(const QString& repo_id,
+ const QString& path,
+ const QString& file_id,
+ const QString& account_sig,
+ const QString& local_file_path);
+
+ QList<CacheEntry> getCachedFilesForDirectory(const QString& account_sig,
+ const QString& repo_id,
+ const QString& parent_dir);
+
+ QList<CacheEntry> getAllCachedFiles();
+ void cleanUnModifiedCacheItemInDatabase(const QString file_id);
+
+private:
+ FileCache();
+ ~FileCache();
+ static bool getCacheEntryCB(sqlite3_stmt *stmt, void *data);
+ static bool collectCachedFile(sqlite3_stmt *stmt, void *data);
+
+ sqlite3 *db_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_DATA_CACHE_H
--- /dev/null
+#include <errno.h>
+#include <cstdio>
+#include <sqlite3.h>
+
+#include <QDir>
+#include <QDateTime>
+
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "auto-update-mgr.h"
+#include "api/requests.h"
+#include "repo-service.h"
+#include "account-mgr.h"
+
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/tasks.h"
+#include "filebrowser/transfer-mgr.h"
+#include "filebrowser/data-cache.h"
+#include "filebrowser/data-mgr.h"
+
+namespace {
+
+const char *kFileCacheTopDirName = "file-cache";
+const int kPasswordCacheExpirationMSecs = 30 * 60 * 1000;
+
+const int kQueryAsyncOperationProgressInterval = 1000;
+} // namespace
+
+/**
+ * Cache loaded dirents. But default cache expires after 1 minute.
+ */
+
+SINGLETON_IMPL(DataManager)
+
+DataManager::DataManager()
+ : filecache_(FileCache::instance()),
+ dirents_cache_(DirentsCache::instance())
+{
+}
+
+DataManager::~DataManager()
+{
+ emit aboutToDestroy();
+ Q_FOREACH(SeafileApiRequest *req, reqs_)
+ {
+ req->deleteLater();
+ }
+}
+
+void DataManager::start()
+{
+ account_ = seafApplet->accountManager()->currentAccount();
+
+ connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+ this, SLOT(onAccountChanged()));
+}
+
+bool DataManager::getDirents(const QString& repo_id,
+ const QString& path,
+ QList<SeafDirent> *dirents,
+ bool *current_readonly)
+{
+ DirentsCache::ReturnEntry retval = dirents_cache_->getCachedDirents(repo_id, path);
+ QList<SeafDirent> *l = retval.second;
+ if (l != NULL) {
+ dirents->append(*l);
+ *current_readonly = retval.first;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void DataManager::getDirentsFromServer(const QString& repo_id,
+ const QString& path)
+{
+ GetDirentsRequest *get_dirents_req = new GetDirentsRequest(account_, repo_id, path);
+ connect(get_dirents_req, SIGNAL(success(bool, const QList<SeafDirent>&, const QString&)),
+ this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent>&, const QString&)));
+ connect(get_dirents_req, SIGNAL(failed(const ApiError&, const QString&)),
+ this, SIGNAL(getDirentsFailed(const ApiError&, const QString&)));
+ get_dirents_req->send();
+ reqs_.push_back(get_dirents_req);
+}
+
+void DataManager::createDirectory(const QString &repo_id,
+ const QString &path)
+{
+ CreateDirectoryRequest *req = new CreateDirectoryRequest(account_, repo_id, path);
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(onCreateDirectorySuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(createDirectoryFailed(const ApiError&)));
+
+ req->send();
+ reqs_.push_back(req);
+}
+
+void DataManager::lockFile(const QString &repo_id,
+ const QString &path,
+ bool lock)
+{
+ LockFileRequest *req = new LockFileRequest(account_, repo_id, path, lock);
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(onLockFileSuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(lockFileFailed(const ApiError&)));
+
+ req->send();
+ reqs_.push_back(req);
+}
+
+void DataManager::renameDirent(const QString &repo_id,
+ const QString &path,
+ const QString &new_path,
+ bool is_file)
+{
+ RenameDirentRequest *req = new RenameDirentRequest(account_, repo_id, path,
+ new_path, is_file);
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(onRenameDirentSuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(renameDirentFailed(const ApiError&)));
+ req->send();
+ reqs_.push_back(req);
+}
+
+
+void DataManager::removeDirent(const QString &repo_id,
+ const QString &path,
+ bool is_file)
+{
+ RemoveDirentRequest *req = new RemoveDirentRequest(account_, repo_id, path,
+ is_file);
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(onRemoveDirentSuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(removeDirentFailed(const ApiError&)));
+ req->send();
+ reqs_.push_back(req);
+}
+
+void DataManager::removeDirents(const QString &repo_id,
+ const QString &parent_path,
+ const QStringList &filenames)
+{
+ RemoveDirentsRequest *req = new RemoveDirentsRequest(account_, repo_id, parent_path,
+ filenames);
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(onRemoveDirentsSuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(removeDirentsFailed(const ApiError&)));
+ req->send();
+ reqs_.push_back(req);
+}
+
+void DataManager::shareDirent(const QString &repo_id,
+ const QString &path,
+ bool is_file)
+{
+ GetSharedLinkRequest *req = new GetSharedLinkRequest(account_, repo_id,
+ path, is_file);
+ connect(req, SIGNAL(success(const QString&, const QString&)),
+ SIGNAL(shareDirentSuccess(const QString&, const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(shareDirentFailed(const ApiError&)));
+ reqs_.push_back(req);
+ req->send();
+}
+
+void DataManager::copyDirents(const QString &repo_id,
+ const QString &dir_path,
+ const QMap<QString, int> &dict_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path)
+{
+ if(copy_move_in_progress_) {
+ seafApplet->warningBox(tr("Another copy or move operation is in progress. Please wait until it finishes."));
+ return;
+ }
+
+ copy_move_in_progress_ = true;
+
+ repo_id_ = repo_id;
+ dir_path_ = dir_path;
+ dst_repo_id_ = dst_repo_id;
+ dst_dir_path_ = dst_dir_path;
+ src_dirents_ = dict_file_names;
+
+ query_async_opera_progress_timer_ = new QTimer(this);
+ query_async_opera_progress_timer_->setInterval(kQueryAsyncOperationProgressInterval);
+ connect(query_async_opera_progress_timer_, SIGNAL(timeout()),
+ this, SLOT(slotQueryAsyncCopyOperaProgress()));
+
+ if (repo_id == dst_repo_id) {
+ QStringList file_names;
+ for(const QString &file_name : dict_file_names.keys()) {
+ file_names.push_back(file_name);
+ }
+
+ CopyMultipleFilesRequest *req =
+ new CopyMultipleFilesRequest(account_,
+ repo_id,
+ dir_path,
+ file_names,
+ dst_repo_id,
+ dst_dir_path);
+
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(onCopyDirentsSuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(copyDirentsFailed(const ApiError&)));
+ reqs_.push_back(req);
+ req->send();
+
+ } else {
+ // First to invoke ssync api v2.1 if async api return 404 ,then invoke v2.0 async api
+ AsyncCopyMultipleItemsRequest *req =
+ new AsyncCopyMultipleItemsRequest(account_,
+ repo_id,
+ dir_path,
+ dict_file_names,
+ dst_repo_id,
+ dst_dir_path);
+
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(slotAsyncCopyMutipleItemsSuccess(const QString&)));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SLOT(slotAsyncCopyMutipleItemsFailed(const ApiError&)));
+ reqs_.push_back(req);
+ req->send();
+ }
+}
+
+void DataManager::slotAsyncCopyMutipleItemsSuccess(const QString& task_id)
+{
+ task_id_ = task_id;
+ is_batch_operation_ = true;
+ query_async_opera_progress_timer_->start();
+}
+
+void DataManager::slotAsyncCopyMutipleItemsFailed(const ApiError& error)
+{
+ if (error.httpErrorCode() == 404) {
+ qWarning("new async copy API is not available on server, use old async copy single item API");
+ asyncCopyOneItemApi();
+ is_batch_operation_ = false;
+ } else {
+ emit copyDirentsFailed(error);
+ copy_move_in_progress_ = false;
+ }
+}
+
+void DataManager::asyncCopyOneItemApi()
+{
+ qWarning("use old sync copy task api");
+ if(src_dirents_.isEmpty()) {
+ copy_move_in_progress_ = false;
+ return ;
+ }
+
+ const QString& filename = src_dirents_.firstKey();
+ async_copy_one_item_req_.reset(new AsyncCopyAndMoveOneItemRequest(account_,
+ repo_id_,
+ dir_path_,
+ filename,
+ dst_repo_id_,
+ dst_dir_path_,
+ "copy",
+ src_dirents_[filename] == 1 ? "DIR" : "FILE"));
+
+ connect(async_copy_one_item_req_.data(), SIGNAL(success(const QString&)),
+ this, SLOT(slotAsyncCopyOneItemSuccess(const QString&)));
+
+ connect(async_copy_one_item_req_.data(), SIGNAL(failed( const ApiError&)),
+ SLOT(slotAsyncCopyOneItemFailed( const ApiError&)));
+
+ async_copy_one_item_req_->send();
+ src_dirents_.remove(filename);
+}
+void DataManager::slotAsyncCopyOneItemSuccess(const QString& task_id)
+{
+ task_id_ = task_id;
+ query_async_opera_progress_timer_->start();
+}
+
+void DataManager::slotAsyncCopyOneItemFailed(const ApiError& error)
+{
+ query_async_opera_progress_timer_->stop();
+ emit copyDirentsFailed(error);
+ copy_move_in_progress_ = false;
+}
+
+void DataManager::slotQueryAsyncCopyOperaProgress()
+{
+ QueryAsyncOperationProgress* query_async_opera_progress_req = new QueryAsyncOperationProgress(account_,
+ task_id_);
+ connect(query_async_opera_progress_req, SIGNAL(success()),
+ this, SLOT(slotQueryAsyncCopyOperationProgressSuccess()));
+
+ connect(query_async_opera_progress_req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(slotQueryAsyncCopyOperationProgressFailed(const ApiError&)));
+
+ query_async_opera_progress_req->send();
+}
+
+void DataManager::slotQueryAsyncCopyOperationProgressSuccess()
+{
+ QueryAsyncOperationProgress * req = qobject_cast<QueryAsyncOperationProgress *>(sender());
+ req->deleteLater();
+ query_async_opera_progress_timer_->stop();
+ onCopyDirentsSuccess(dst_repo_id_);
+ if (!is_batch_operation_) {
+ asyncCopyOneItemApi();
+ } else {
+ copy_move_in_progress_ = false;
+ }
+}
+
+void DataManager::slotQueryAsyncCopyOperationProgressFailed(const ApiError& error)
+{
+ QueryAsyncOperationProgress * req = qobject_cast<QueryAsyncOperationProgress *>(sender());
+ req->deleteLater();
+ query_async_opera_progress_timer_->stop();
+ emit copyDirentsFailed(error);
+ copy_move_in_progress_ = false;
+}
+
+void DataManager::moveDirents(const QString &repo_id,
+ const QString &dir_path,
+ const QMap<QString, int> &dict_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path)
+{
+
+ if(copy_move_in_progress_) {
+ seafApplet->warningBox(tr("Another copy or move operation is in progress. Please wait until it finishes."));
+ return;
+ }
+
+ copy_move_in_progress_ = true;
+
+ repo_id_ = repo_id;
+ dir_path_ = dir_path;
+ dst_repo_id_ = dst_repo_id;
+ dst_dir_path_ = dst_dir_path;
+ src_dirents_ = dict_file_names;
+
+
+ query_async_opera_progress_timer_ = new QTimer(this);
+ query_async_opera_progress_timer_->setInterval(kQueryAsyncOperationProgressInterval);
+ connect(query_async_opera_progress_timer_, SIGNAL(timeout()),
+ this, SLOT(slotQueryAsyncMoveOperaProgress()));
+
+ if (repo_id == dst_repo_id) {
+ QStringList file_names;
+ for(const QString &file_name : dict_file_names.keys()) {
+ file_names.push_back(file_name);
+ }
+
+ MoveMultipleFilesRequest *req =
+ new MoveMultipleFilesRequest(account_,
+ repo_id, dir_path, file_names,
+ dst_repo_id,
+ dst_dir_path);
+
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(onMoveDirentsSuccess(const QString&)));
+
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SIGNAL(moveDirentsFailed(const ApiError&)));
+ reqs_.push_back(req);
+ req->send();
+ } else {
+ // First to invoke ssync api v2.1 if async api return 404 ,then invoke v2.0 async api
+ AsyncMoveMultipleItemsRequest *req =
+ new AsyncMoveMultipleItemsRequest(account_,
+ repo_id,
+ dir_path,
+ dict_file_names,
+ dst_repo_id,
+ dst_dir_path);
+
+ connect(req, SIGNAL(success(const QString&)),
+ SLOT(slotAsyncMoveMutipleItemsSuccess(const QString&)));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ SLOT(slotAsyncMoveMutipleItemsFailed(const ApiError&)));
+ reqs_.push_back(req);
+ req->send();
+ }
+}
+
+void DataManager::slotAsyncMoveMutipleItemsSuccess(const QString& task_id)
+{
+ task_id_ = task_id;
+ is_batch_operation_ = true;
+ query_async_opera_progress_timer_->start();
+}
+
+void DataManager::slotAsyncMoveMutipleItemsFailed(const ApiError& error)
+{
+ if (error.httpErrorCode() == 404) {
+ qWarning("new async move API is not available on server, use old async move single item API");
+ asyncMoveOneItemApi();
+ is_batch_operation_ = false;
+ } else {
+ emit moveDirentsFailed(error);
+ copy_move_in_progress_ = false;
+ }
+}
+
+void DataManager::asyncMoveOneItemApi()
+{
+ qWarning("use async move one item API");
+ if(src_dirents_.isEmpty()) {
+ copy_move_in_progress_ = false;
+ return ;
+ }
+
+ const QString& filename = src_dirents_.firstKey();
+ async_copy_one_item_req_.reset(new AsyncCopyAndMoveOneItemRequest(account_,
+ repo_id_,
+ dir_path_,
+ filename,
+ dst_repo_id_,
+ dst_dir_path_,
+ "move",
+ src_dirents_[filename] == 1 ? "DIR" : "FILE"));
+
+ connect(async_copy_one_item_req_.data(), SIGNAL(success(const QString&)),
+ this, SLOT(slotAsyncMoveOneItemSuccess(const QString&)));
+
+ connect(async_copy_one_item_req_.data(), SIGNAL(failed( const ApiError&)),
+ SLOT(slotAsyncMoveOneItemFailed( const ApiError&)));
+
+ async_copy_one_item_req_->send();
+ src_dirents_.remove(filename);
+}
+
+void DataManager::slotAsyncMoveOneItemSuccess(const QString& task_id)
+{
+ task_id_ = task_id;
+ query_async_opera_progress_timer_->start();
+}
+
+void DataManager::slotAsyncMoveOneItemFailed(const ApiError& error)
+{
+ query_async_opera_progress_timer_->stop();
+ emit moveDirentsFailed(error);
+ copy_move_in_progress_ = false;
+}
+
+void DataManager::slotQueryAsyncMoveOperaProgress()
+{
+ QueryAsyncOperationProgress* query_async_opera_progress_req = new QueryAsyncOperationProgress(account_,
+ task_id_);
+ connect(query_async_opera_progress_req, SIGNAL(success()),
+ this, SLOT(slotQueryAsyncMoveOperationProgressSuccess()));
+
+ connect(query_async_opera_progress_req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(slotQueryAsyncMoveOperationProgressFailed(const ApiError&)));
+
+ query_async_opera_progress_req->send();
+}
+
+void DataManager::slotQueryAsyncMoveOperationProgressSuccess()
+{
+ QueryAsyncOperationProgress * req = qobject_cast<QueryAsyncOperationProgress *>(sender());
+ req->deleteLater();
+ query_async_opera_progress_timer_->stop();
+ dirents_cache_->expireCachedDirents(repo_id_, dir_path_);
+ moveDirentsSuccess(dst_repo_id_);
+ if (!is_batch_operation_) {
+ asyncMoveOneItemApi();
+ } else {
+ copy_move_in_progress_ = false;
+ }
+}
+
+void DataManager::slotQueryAsyncMoveOperationProgressFailed(const ApiError& error)
+{
+ QueryAsyncOperationProgress * req = qobject_cast<QueryAsyncOperationProgress *>(sender());
+ req->deleteLater();
+ query_async_opera_progress_timer_->stop();
+ emit moveDirentsFailed(error);
+ copy_move_in_progress_ = false;
+}
+
+
+void DataManager::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents, const QString& repo_id)
+{
+ GetDirentsRequest *get_dirents_req = qobject_cast<GetDirentsRequest *>(sender());
+ dirents_cache_->saveCachedDirents(get_dirents_req->repoId(),
+ get_dirents_req->path(),
+ current_readonly,
+ dirents);
+
+ emit getDirentsSuccess(current_readonly, dirents, repo_id);
+}
+
+void DataManager::onCreateDirectorySuccess(const QString& repo_id)
+{
+ CreateDirectoryRequest *req = qobject_cast<CreateDirectoryRequest*>(sender());
+
+ if(req == NULL)
+ return;
+
+ removeDirentsCache(req->repoId(), req->path(), false);
+ emit createDirectorySuccess(req->path(), repo_id);
+}
+
+void DataManager::onLockFileSuccess(const QString& repo_id)
+{
+ LockFileRequest *req = qobject_cast<LockFileRequest *>(sender());
+ if (!req)
+ return;
+
+ removeDirentsCache(req->repoId(), req->path(), false);
+ seafApplet->rpcClient()->markFileLockState(req->repoId(), req->path(), req->lock());
+ emit lockFileSuccess(req->path(), req->lock(), repo_id);
+}
+
+void DataManager::onRenameDirentSuccess(const QString& repo_id)
+{
+ RenameDirentRequest *req = qobject_cast<RenameDirentRequest*>(sender());
+
+ if(req == NULL)
+ return;
+
+ removeDirentsCache(req->repoId(), req->path(), req->isFile());
+ emit renameDirentSuccess(req->path(), req->newName(), repo_id);
+}
+
+void DataManager::onRemoveDirentSuccess(const QString& repo_id)
+{
+ RemoveDirentRequest *req = qobject_cast<RemoveDirentRequest*>(sender());
+
+ if(req == NULL)
+ return;
+
+ removeDirentsCache(req->repoId(), req->path(), req->isFile());
+ emit removeDirentSuccess(req->path(), repo_id);
+}
+
+void DataManager::onRemoveDirentsSuccess(const QString& repo_id)
+{
+ RemoveDirentsRequest *req = qobject_cast<RemoveDirentsRequest*>(sender());
+
+ if(req == NULL)
+ return;
+
+ removeDirentsCache(req->repoId(), req->parentPath(), false);
+ emit removeDirentsSuccess(req->parentPath(), req->filenames(), repo_id);
+}
+
+void DataManager::onCopyDirentsSuccess(const QString& dst_repo_id)
+{
+ emit copyDirentsSuccess(dst_repo_id);
+}
+
+void DataManager::onMoveDirentsSuccess(const QString& dst_repo_id)
+{
+ MoveMultipleFilesRequest *req = qobject_cast<MoveMultipleFilesRequest*>(sender());
+ dirents_cache_->expireCachedDirents(req->srcRepoId(), req->srcPath());
+
+ emit moveDirentsSuccess(dst_repo_id);
+}
+
+void DataManager::removeDirentsCache(const QString& repo_id,
+ const QString& path,
+ bool is_file)
+{
+ // expire its parent's cache
+ dirents_cache_->expireCachedDirents(repo_id, ::getParentPath(path));
+ // if the object is a folder, then expire its self cache
+ if (!is_file)
+ dirents_cache_->expireCachedDirents(repo_id, path);
+}
+
+
+QString DataManager::getLocalCachedFile(const QString& repo_id,
+ const QString& fpath,
+ const QString& file_id)
+{
+ QString local_file_path = getLocalCacheFilePath(repo_id, fpath);
+ QFileInfo finfo(local_file_path);
+ if (!finfo.exists()) {
+ qWarning ("No cache file for %s\n", toCStr(fpath));
+ return "";
+ }
+
+ FileCache::CacheEntry entry;
+ if (!filecache_->getCacheEntry(repo_id, fpath, &entry)) {
+ qWarning ("No cache db entry for %s\n", toCStr(fpath));
+ return "";
+ }
+
+ if (entry.file_id == file_id) {
+ qWarning ("cache file id matched for %s: %s\n", toCStr(fpath), toCStr(file_id));
+ return local_file_path;
+ } else {
+ // The file is updated on server
+ qint64 mtime = finfo.lastModified().toMSecsSinceEpoch();
+ bool use_cached = false;
+ if (mtime != entry.seafile_mtime) {
+ qWarning(
+ "cache file is updated locally (mtime changed from %lld to "
+ "%lld), use it: %s\n",
+ entry.seafile_mtime,
+ mtime,
+ toCStr(fpath));
+ use_cached = true;
+ } else if (finfo.size() != entry.seafile_size) {
+ qWarning(
+ "cache file is updated locally (size changed from %lld to "
+ "%lld), use it: %s\n",
+ entry.seafile_size,
+ finfo.size(),
+ toCStr(fpath));
+ use_cached = true;
+ }
+
+ if (use_cached) {
+ // If the file is also updated locally, open it directly
+ return local_file_path;
+ } else {
+ qWarning ("cache file is outdated, download newer version: %s\n", toCStr(fpath));
+ // Otherwise the newer version would be downloaded
+ return "";
+ }
+ }
+}
+
+FileDownloadTask* DataManager::createDownloadTask(const QString& repo_id,
+ const QString& path)
+{
+ QString local_path = getLocalCacheFilePath(repo_id, path);
+ FileDownloadTask* task = TransferManager::instance()->addDownloadTask(
+ account_, repo_id, path, local_path);
+ connect(task, SIGNAL(finished(bool)),
+ this, SLOT(onFileDownloadFinished(bool)), Qt::UniqueConnection);
+ setupTaskCleanup(task);
+
+ return task;
+}
+
+FileDownloadTask* DataManager::createSaveAsTask(const QString& repo_id,
+ const QString& path,
+ const QString& local_path)
+{
+ FileDownloadTask* task = TransferManager::instance()->addDownloadTask(
+ account_, repo_id, path, local_path, true);
+ setupTaskCleanup(task);
+
+ return task;
+}
+
+void DataManager::onFileDownloadFinished(bool success)
+{
+ qDebug("[onFileDownloadFinished function] invoked,is success %s",
+ success ? "true" : "false");
+ FileDownloadTask *task = qobject_cast<FileDownloadTask *>(sender());
+ if (task == NULL)
+ return;
+ if (success) {
+ filecache_->saveCachedFileId(task->repoId(),
+ task->path(),
+ account_.getSignature(),
+ task->fileId(),
+ task->localFilePath());
+ // TODO we don't want to watch readonly files
+ AutoUpdateManager::instance()->watchCachedFile(account_, task->repoId(), task->path());
+ }
+}
+
+FileUploadTask* DataManager::createUploadTask(const QString& repo_id,
+ const QString& parent_dir,
+ const QString& local_path,
+ const QString& name,
+ const bool overwrite)
+{
+ FileUploadTask *task;
+ if (QFileInfo(local_path).isFile())
+ task = new FileUploadTask(account_, repo_id, parent_dir,
+ local_path, name, !overwrite);
+ else
+ task = new FileUploadDirectoryTask(account_, repo_id, parent_dir,
+ local_path, name);
+ connect(task, SIGNAL(finished(bool)),
+ this, SLOT(onFileUploadFinished(bool)));
+ setupTaskCleanup(task);
+
+ return task;
+}
+
+void DataManager::setupTaskCleanup(FileNetworkTask *task)
+{
+ connect(this, SIGNAL(aboutToDestroy()),
+ task, SLOT(cancel()));
+}
+
+FileUploadTask* DataManager::createUploadMultipleTask(const QString& repo_id,
+ const QString& parent_dir,
+ const QString& local_path,
+ const QStringList& names,
+ const bool overwrite)
+{
+ FileUploadTask *task = new FileUploadMultipleTask(account_, repo_id, parent_dir,
+ local_path, names, !overwrite);
+
+ connect(task, SIGNAL(finished(bool)),
+ this, SLOT(onFileUploadFinished(bool)));
+ setupTaskCleanup(task);
+
+ return task;
+}
+
+void DataManager::onFileUploadFinished(bool success)
+{
+ FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+ if (task == NULL)
+ return;
+ if (success) {
+ //expire the parent path
+ dirents_cache_->expireCachedDirents(task->repoId(),
+ task->path());
+ }
+}
+
+QString DataManager::getLocalCacheFilePath(const QString& repo_id,
+ const QString& path)
+{
+ QString seafdir = seafApplet->configurator()->seafileDir();
+ return ::pathJoin(seafdir, kFileCacheTopDirName, repo_id, path);
+}
+
+QHash<QString, std::pair<qint64, QString> > DataManager::passwords_cache_;
+
+bool DataManager::isRepoPasswordSet(const QString& repo_id) const
+{
+ if (!passwords_cache_.contains(repo_id)) {
+ return false;
+ }
+ qint64 expiration_time = passwords_cache_[repo_id].first;
+ qint64 now = QDateTime::currentMSecsSinceEpoch();
+ return now < expiration_time;
+}
+
+void DataManager::setRepoPasswordSet(const QString& repo_id, const QString& password)
+{
+ passwords_cache_[repo_id] =
+ std::pair<qint64, QString>(QDateTime::currentMSecsSinceEpoch() + kPasswordCacheExpirationMSecs, password);
+}
+
+QString DataManager::getRepoCacheFolder(const QString& repo_id) const
+{
+ QString seafdir = seafApplet->configurator()->seafileDir();
+ return ::pathJoin(seafdir, kFileCacheTopDirName, repo_id);
+}
+
+void DataManager::createSubrepo(const QString &name, const QString& repo_id, const QString &path)
+{
+ old_repo_id_ = repo_id;
+ const QString password = repoPassword(repo_id);
+ const QString fixed_path = path.left(path.endsWith('/') && path.size() != 1 ? path.size() -1 : path.size());
+ create_subrepo_req_.reset(new CreateSubrepoRequest(account_, name, repo_id, fixed_path, password));
+ // we might have cleaned this value when do a new request while old request is still there
+ get_repo_req_.reset(NULL);
+ create_subrepo_parent_repo_id_ = repo_id;
+ create_subrepo_parent_path_ = fixed_path;
+
+ connect(create_subrepo_req_.data(), SIGNAL(success(const QString&)),
+ this, SLOT(onCreateSubrepoSuccess(const QString&)));
+ connect(create_subrepo_req_.data(), SIGNAL(failed(const ApiError&)),
+ this, SIGNAL(createSubrepoFailed(const ApiError&)));
+
+ create_subrepo_req_->send();
+}
+
+void DataManager::onCreateSubrepoSuccess(const QString& new_repoid)
+{
+ // if we have it, we are lucky
+ ServerRepo repo = RepoService::instance()->getRepo(new_repoid);
+ if (repo.isValid()) {
+ ServerRepo fixed_repo = repo;
+ fixed_repo.parent_path = create_subrepo_parent_path_;
+ fixed_repo.parent_repo_id = create_subrepo_parent_repo_id_;
+ emit createSubrepoSuccess(fixed_repo, old_repo_id_);
+ return;
+ }
+
+ // if not found, we need call get repo (list repo is not reliable here)
+ get_repo_req_.reset(new GetRepoRequest(account_, new_repoid));
+
+ // connect
+ connect(get_repo_req_.data(), SIGNAL(success(const ServerRepo&)),
+ this, SLOT(onCreateSubrepoRefreshSuccess(const ServerRepo&)));
+ connect(get_repo_req_.data(), SIGNAL(failed(const ApiError&)),
+ this, SIGNAL(createSubrepoFailed(const ApiError&)));
+
+ get_repo_req_->send();
+}
+
+void DataManager::onCreateSubrepoRefreshSuccess(const ServerRepo& repo)
+{
+ // okay, all green
+ if (repo.isValid()) {
+ ServerRepo fixed_repo = repo;
+ fixed_repo.parent_path = create_subrepo_parent_path_;
+ fixed_repo.parent_repo_id = create_subrepo_parent_repo_id_;
+ emit createSubrepoSuccess(fixed_repo, old_repo_id_);
+ return;
+ }
+
+ // it is not expected
+ emit createSubrepoFailed(ApiError::fromHttpError(500));
+}
+
+void DataManager::onAccountChanged()
+{
+ account_ = seafApplet->accountManager()->currentAccount();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_DATA_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_DATA_MANAGER_H
+
+#include <QObject>
+#include <QHash>
+#include <QScopedPointer>
+#include <utility>
+
+#include "api/api-error.h"
+#include "account.h"
+#include "seaf-dirent.h"
+#include "utils/singleton.h"
+
+
+template<typename Key> class QList;
+
+class SeafileApiRequest;
+class GetDirentsRequest;
+class GetRepoRequest;
+class CreateSubrepoRequest;
+class DirentsCache;
+class FileCache;
+class FileCache;
+class FileNetworkTask;
+class FileUploadTask;
+class FileDownloadTask;
+class QueryAsyncOperationProgress;
+class AsyncCopyAndMoveOneItemRequest;
+
+/**
+ * DataManager is responsible for getting dirents/files from seahub, as well
+ * as the caching policy.
+ *
+ */
+class DataManager : public QObject {
+ SINGLETON_DEFINE(DataManager)
+ Q_OBJECT
+
+public:
+ DataManager();
+ ~DataManager();
+
+ void start();
+
+ const Account& account() const { return account_; }
+
+ bool getDirents(const QString& repo_id,
+ const QString& path,
+ QList<SeafDirent> *dirents,
+ bool *current_readonly);
+
+ void getDirentsFromServer(const QString& repo_id,
+ const QString& path);
+
+ void createDirectory(const QString &repo_id,
+ const QString &path);
+
+ void renameDirent(const QString &repo_id,
+ const QString &path,
+ const QString &new_path,
+ bool is_file);
+
+ void lockFile(const QString &repo_id,
+ const QString &path,
+ bool lock);
+
+ void removeDirent(const QString &repo_id,
+ const QString &path,
+ bool is_file);
+
+ void removeDirents(const QString &repo_id,
+ const QString &parent_path,
+ const QStringList &filenames);
+
+ void shareDirent(const QString &repo_id,
+ const QString &path,
+ bool is_file);
+
+ void copyDirents(const QString &repo_id,
+ const QString &dir_path,
+ const QMap<QString, int> &dict_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path);
+
+ void moveDirents(const QString &repo_id,
+ const QString &dir_path,
+ const QMap<QString, int> &dict_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path);
+
+ QString getLocalCachedFile(const QString& repo_id,
+ const QString& path,
+ const QString& file_id);
+
+ FileDownloadTask* createDownloadTask(const QString& repo_id,
+ const QString& path);
+
+ FileDownloadTask* createSaveAsTask(const QString& repo_id,
+ const QString& path,
+ const QString& local_path);
+
+ FileUploadTask* createUploadTask(const QString& repo_id,
+ const QString& parent_dir,
+ const QString& local_path,
+ const QString& name,
+ const bool overwrite);
+
+ FileUploadTask* createUploadMultipleTask(const QString& repo_id,
+ const QString& parent_dir,
+ const QString& local_path,
+ const QStringList& names,
+ const bool overwrite);
+
+ bool isRepoPasswordSet(const QString& repo_id) const;
+ QString repoPassword(const QString& repo_id) const {
+ if (!isRepoPasswordSet(repo_id))
+ return QString();
+ return passwords_cache_[repo_id].second;
+ }
+ void setRepoPasswordSet(const QString& repo_id, const QString& password);
+
+ QString getRepoCacheFolder(const QString& repo_id) const;
+
+ static QString getLocalCacheFilePath(const QString& repo_id,
+ const QString& path);
+
+ void createSubrepo(const QString &name, const QString& repo_id, const QString &path);
+
+signals:
+ void aboutToDestroy();
+
+ void getDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id);
+ void getDirentsFailed(const ApiError& error, const QString& repo_id);
+
+ void createDirectorySuccess(const QString& path, const QString& repo_id);
+ void createDirectoryFailed(const ApiError& error);
+
+ void lockFileSuccess(const QString& path, bool lock, const QString& repo_id);
+ void lockFileFailed(const ApiError& error);
+
+ void renameDirentSuccess(const QString& path, const QString& new_name, const QString& repo_id);
+ void renameDirentFailed(const ApiError& error);
+
+ void removeDirentSuccess(const QString& path, const QString& repo_id);
+ void removeDirentFailed(const ApiError& error);
+
+ void removeDirentsSuccess(const QString& parent_path, const QStringList& filenames, const QString& repo_id);
+ void removeDirentsFailed(const ApiError& error);
+
+ void shareDirentSuccess(const QString& link, const QString& repo_id);
+ void shareDirentFailed(const ApiError& error);
+
+ void copyDirentsSuccess(const QString& dst_repo_id);
+ void copyDirentsFailed(const ApiError& error);
+
+ void moveDirentsSuccess(const QString& dst_repo_id);
+ void moveDirentsFailed(const ApiError& error);
+
+ void createSubrepoSuccess(const ServerRepo &repo, const QString& repo_id);
+ void createSubrepoFailed(const ApiError& error);
+
+private slots:
+ void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id);
+ void onFileUploadFinished(bool success);
+ void onFileDownloadFinished(bool success);
+
+ void onCreateDirectorySuccess(const QString& repo_id);
+ void onLockFileSuccess(const QString& repo_id);
+ void onRenameDirentSuccess(const QString& repo_id);
+ void onRemoveDirentSuccess(const QString& repo_id);
+ void onRemoveDirentsSuccess(const QString& repo_id);
+ void onCopyDirentsSuccess(const QString& dst_repo_id);
+ void onMoveDirentsSuccess(const QString& dst_repo_id);
+
+ void onCreateSubrepoSuccess(const QString& new_repoid);
+ void onCreateSubrepoRefreshSuccess(const ServerRepo& new_repo);
+
+ void onAccountChanged();
+
+public slots:
+ // async copy operation
+ void slotAsyncCopyMutipleItemsSuccess(const QString& task_id);
+ void slotAsyncCopyMutipleItemsFailed(const ApiError& error);
+ void asyncCopyOneItemApi();
+ void slotAsyncCopyOneItemSuccess(const QString& task_id);
+ void slotAsyncCopyOneItemFailed(const ApiError& error);
+ void slotQueryAsyncCopyOperaProgress();
+ void slotQueryAsyncCopyOperationProgressSuccess();
+ void slotQueryAsyncCopyOperationProgressFailed(const ApiError& error);
+
+ // async move operations
+ void slotAsyncMoveMutipleItemsSuccess(const QString& task_id);
+ void slotAsyncMoveMutipleItemsFailed(const ApiError& error);
+ void asyncMoveOneItemApi();
+ void slotAsyncMoveOneItemSuccess(const QString& task_id);
+ void slotAsyncMoveOneItemFailed(const ApiError& error);
+ void slotQueryAsyncMoveOperaProgress();
+ void slotQueryAsyncMoveOperationProgressSuccess();
+ void slotQueryAsyncMoveOperationProgressFailed(const ApiError& error);
+
+private:
+ void removeDirentsCache(const QString& repo_id,
+ const QString& path,
+ bool is_file);
+ void setupTaskCleanup(FileNetworkTask *task);
+ Account account_;
+
+ QScopedPointer<CreateSubrepoRequest, QScopedPointerDeleteLater> create_subrepo_req_;
+ QString create_subrepo_parent_repo_id_;
+ QString create_subrepo_parent_path_;
+ QScopedPointer<GetRepoRequest, QScopedPointerDeleteLater> get_repo_req_;
+
+ QList<SeafileApiRequest*> reqs_;
+
+ FileCache *filecache_;
+
+ DirentsCache *dirents_cache_;
+ QString old_repo_id_;
+
+ // copy and move struct
+ QMap<QString, int> src_dirents_;
+ QString repo_id_;
+ QString dir_path_;
+ QString dst_repo_id_;
+ QString dst_dir_path_;
+ bool is_batch_operation_;
+ QString task_id_;
+
+ static QHash<QString, std::pair<qint64, QString> > passwords_cache_;
+ QTimer* query_async_opera_progress_timer_;
+ QScopedPointer<AsyncCopyAndMoveOneItemRequest, QScopedPointerDeleteLater> async_copy_one_item_req_;
+ bool copy_move_in_progress_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_DATA_MANAGER_H
--- /dev/null
+#include <QtGlobal>
+#include <QtWidgets>
+#include <QDesktopServices>
+#include <QHBoxLayout>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "utils/file-utils.h"
+#include "api/api-error.h"
+#include "file-table.h"
+#include "seaf-dirent.h"
+#include "ui/loading-view.h"
+#include "data-mgr.h"
+#include "data-mgr.h"
+#include "progress-dialog.h"
+#include "tasks.h"
+#include "ui/set-repo-password-dialog.h"
+#include "sharedlink-dialog.h"
+#include "seafilelink-dialog.h"
+#include "auto-update-mgr.h"
+#include "transfer-mgr.h"
+#include "repo-service.h"
+#include "rpc/local-repo.h"
+#include "rpc/rpc-client.h"
+#include "ui/private-share-dialog.h"
+#include "ui/logout-view.h"
+
+#include "file-browser-manager.h"
+#include "file-browser-dialog.h"
+
+#include "ui/download-repo-dialog.h"
+
+#include "QtAwesome.h"
+
+namespace {
+
+enum {
+ INDEX_LOADING_VIEW = 0,
+ INDEX_TABLE_VIEW,
+ INDEX_LOADING_FAILED_VIEW,
+ INDEX_EMPTY_VIEW,
+ INDEX_RELOGIN_VIEW,
+ INDEX_SEARCH_VIEW
+};
+
+const char *kLoadingFailedLabelName = "LoadingFailedText";
+const int kToolBarIconSize = 24;
+const int kStatusBarIconSize = 20;
+const int kAllPage = 1;
+const int kPerPageCount = 10000;
+const int kSearchBarWidth = 250;
+//const int kStatusCodePasswordNeeded = 400;
+
+void openFile(const QString& path)
+{
+ ::openInNativeExtension(path) || ::showInGraphicalShell(path);
+#ifdef Q_OS_MAC
+ MacImageFilesWorkAround::instance()->fileOpened(path);
+#endif
+}
+
+bool inline findConflict(const QString &name, const QList<SeafDirent> &dirents) {
+ bool found_conflict = false;
+ // find if there exist a file with the same name
+ Q_FOREACH(const SeafDirent &dirent, dirents)
+ {
+ if (dirent.name == name) {
+ found_conflict = true;
+ break;
+ }
+ }
+ return found_conflict;
+}
+
+QString appendTrailingSlash(const QString& input) {
+ return input.endsWith('/') ? input : input + '/';
+}
+
+} // namespace
+
+QMap<QString, int> FileBrowserDialog::file_names_to_be_pasted_;
+QString FileBrowserDialog::dir_path_to_be_pasted_from_;
+QString FileBrowserDialog::repo_id_to_be_pasted_from_;
+Account FileBrowserDialog::account_to_be_pasted_from_;
+bool FileBrowserDialog::is_copyed_when_pasted_;
+
+FileBrowserDialog::FileBrowserDialog(const Account &account, const ServerRepo& repo, const QString &path, QWidget *parent)
+ : QDialog(parent),
+ account_(account),
+ repo_(repo),
+ current_path_(path),
+ current_readonly_(repo_.readonly),
+ search_request_(NULL),
+ search_text_last_modified_(0),
+ has_password_dialog_(false)
+{
+ current_lpath_ = current_path_.split('/');
+
+ data_mgr_ = seafApplet->dataManager();
+
+ // In German translation there is a "seafile" string, so need to use tr("..").arg(..) here
+ QString title = tr("Cloud File Browser");
+ if (title.contains("%")) {
+ title = title.arg(getBrand());
+ }
+ setWindowTitle(title);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ Qt::WindowFlags flags =
+ (windowFlags() & ~Qt::WindowContextHelpButtonHint & ~Qt::Dialog) |
+ Qt::Window | Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint |
+ Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint |
+ Qt::WindowMaximizeButtonHint;
+
+ setWindowFlags(flags);
+
+ // setAttribute(Qt::WA_TranslucentBackground, true);
+
+ createToolBar();
+ createStatusBar();
+ createLoadingFailedView();
+ createEmptyView();
+ createFileTable();
+
+ relogin_view_ = new LogoutView;
+
+ QWidget* widget = new QWidget;
+ widget->setObjectName("mainWidget");
+ QVBoxLayout* layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ setLayout(layout);
+ layout->addWidget(widget);
+
+ QVBoxLayout *vlayout = new QVBoxLayout;
+ vlayout->setContentsMargins(1, 0, 1, 0);
+ vlayout->setSpacing(0);
+ widget->setLayout(vlayout);
+
+ QHBoxLayout *hlayout = new QHBoxLayout;
+ hlayout->setContentsMargins(1, 0, 1, 0);
+ hlayout->setSpacing(0);
+ hlayout->addWidget(toolbar_);
+ hlayout->addWidget(search_toolbar_);
+
+ search_view_ = new FileBrowserSearchView(this);
+ search_view_->setObjectName("searchResult");
+#ifdef Q_OS_MAC
+ search_view_->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+ search_model_ = new FileBrowserSearchModel(this);
+ search_view_->setModel(search_model_);
+ search_view_->setColumnWidth(0,265);
+ search_view_->setColumnWidth(1,165);
+ search_view_->setColumnWidth(2,95);
+ search_delegate_ = new FileBrowserSearchItemDelegate(this);
+ delete search_view_->itemDelegate();
+ search_view_->setItemDelegate(search_delegate_);
+
+ stack_ = new QStackedWidget;
+ stack_->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+ stack_->insertWidget(INDEX_TABLE_VIEW, table_view_);
+ stack_->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+ stack_->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+ stack_->insertWidget(INDEX_RELOGIN_VIEW, relogin_view_);
+ stack_->insertWidget(INDEX_SEARCH_VIEW, search_view_);
+ stack_->setContentsMargins(0, 0, 0, 0);
+ stack_->installEventFilter(this);
+ stack_->setAcceptDrops(true);
+
+ vlayout->addLayout(hlayout);
+ vlayout->addWidget(stack_);
+ vlayout->addWidget(status_bar_);
+
+ search_timer_ = new QTimer(this);
+ connect(search_timer_, SIGNAL(timeout()), this, SLOT(doRealSearch()));
+ search_timer_->start(300);
+
+ // this <--> table_view_
+ connect(table_view_, SIGNAL(direntClicked(const SeafDirent&)),
+ this, SLOT(onDirentClicked(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntSaveAs(const QList<const SeafDirent*>&)),
+ this, SLOT(onDirentSaveAs(const QList<const SeafDirent*>&)));
+ connect(table_view_, SIGNAL(direntLock(const SeafDirent&)),
+ this, SLOT(onGetDirentLock(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntRename(const SeafDirent&)),
+ this, SLOT(onGetDirentRename(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntRemove(const SeafDirent&)),
+ this, SLOT(onGetDirentRemove(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntRemove(const QList<const SeafDirent*> &)),
+ this, SLOT(onGetDirentRemove(const QList<const SeafDirent*> &)));
+ connect(table_view_, SIGNAL(direntShare(const SeafDirent&)),
+ this, SLOT(onGetDirentShare(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntShareToUserOrGroup(const SeafDirent&, bool)),
+ this, SLOT(onGetDirentShareToUserOrGroup(const SeafDirent&, bool)));
+ connect(table_view_, SIGNAL(direntShareSeafile(const SeafDirent&)),
+ this, SLOT(onGetDirentShareSeafile(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntUploadLink(const SeafDirent&)),
+ this, SLOT(onGetDirentUploadLink(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntUpdate(const SeafDirent&)),
+ this, SLOT(onGetDirentUpdate(const SeafDirent&)));
+ connect(table_view_, SIGNAL(direntPaste()),
+ this, SLOT(onGetDirentsPaste()));
+ connect(table_view_, SIGNAL(cancelDownload(const SeafDirent&)),
+ this, SLOT(onCancelDownload(const SeafDirent&)));
+ connect(table_view_, SIGNAL(syncSubdirectory(const QString&)),
+ this, SLOT(onGetSyncSubdirectory(const QString &)));
+ connect(table_view_, SIGNAL(deleteLocalVersion(const SeafDirent&)),
+ this, SLOT(onDeleteLocalVersion(const SeafDirent&)));
+ connect(table_view_, SIGNAL(localVersionSaveAs(const SeafDirent&)),
+ this, SLOT(onLocalVersionSaveAs(const SeafDirent&)));
+
+ connect(search_view_, SIGNAL(clearSearchBar()),
+ search_bar_, SLOT(clear()));
+
+
+ //dirents <--> data_mgr_
+ data_mgr_notify_ = new DataManagerNotify(repo_.id);
+ connect(data_mgr_notify_, SIGNAL(getDirentsSuccess(bool, const QList<SeafDirent>&)),
+ this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent>&)));
+ connect(data_mgr_notify_, SIGNAL(getDirentsFailed(const ApiError&)),
+ this, SLOT(onGetDirentsFailed(const ApiError&)));
+
+ //create <--> data_mgr_
+ connect(data_mgr_notify_, SIGNAL(createDirectorySuccess(const QString&)),
+ this, SLOT(onDirectoryCreateSuccess(const QString&)));
+ connect(data_mgr_, SIGNAL(createDirectoryFailed(const ApiError&)),
+ this, SLOT(onDirectoryCreateFailed(const ApiError&)));
+
+ //lock <--> data_mgr_
+ connect(data_mgr_notify_, SIGNAL(lockFileSuccess(const QString&, bool)),
+ this, SLOT(onFileLockSuccess(const QString&, bool)));
+ connect(data_mgr_, SIGNAL(lockFileFailed(const ApiError&)),
+ this, SLOT(onFileLockFailed(const ApiError&)));
+
+ //rename <--> data_mgr_
+ connect(data_mgr_notify_, SIGNAL(renameDirentSuccess(const QString&, const QString&)),
+ this, SLOT(onDirentRenameSuccess(const QString&, const QString&)));
+ connect(data_mgr_, SIGNAL(renameDirentFailed(const ApiError&)),
+ this, SLOT(onDirentRenameFailed(const ApiError&)));
+
+ //remove <--> data_mgr_
+ connect(data_mgr_notify_, SIGNAL(removeDirentSuccess(const QString&)),
+ this, SLOT(onDirentRemoveSuccess(const QString&)));
+ connect(data_mgr_, SIGNAL(removeDirentFailed(const ApiError&)),
+ this, SLOT(onDirentRemoveFailed(const ApiError&)));
+
+ connect(data_mgr_notify_, SIGNAL(removeDirentsSuccess(const QString&, const QStringList&)),
+ this, SLOT(onDirentsRemoveSuccess(const QString&, const QStringList&)));
+ connect(data_mgr_, SIGNAL(removeDirentsFailed(const ApiError&)),
+ this, SLOT(onDirentsRemoveFailed(const ApiError&)));
+
+ //share <--> data_mgr_
+ connect(data_mgr_notify_, SIGNAL(shareDirentSuccess(const QString&)),
+ this, SLOT(onDirentShareSuccess(const QString&)));
+ connect(data_mgr_, SIGNAL(shareDirentFailed(const ApiError&)),
+ this, SLOT(onDirentShareFailed(const ApiError&)));
+
+ //copy <--> data_mgr_
+ connect(data_mgr_notify_, SIGNAL(copyDirentsSuccess()),
+ this, SLOT(onDirentsCopySuccess()));
+ connect(data_mgr_, SIGNAL(copyDirentsFailed(const ApiError&)),
+ this, SLOT(onDirentsCopyFailed(const ApiError&)));
+
+ //move <--> data_mgr_
+ connect(data_mgr_notify_, SIGNAL(moveDirentsSuccess()),
+ this, SLOT(onDirentsMoveSuccess()));
+ connect(data_mgr_, SIGNAL(moveDirentsFailed(const ApiError&)),
+ this, SLOT(onDirentsMoveFailed(const ApiError&)));
+
+ //subrepo <-->data_mgr_
+ connect(data_mgr_notify_, SIGNAL(createSubrepoSuccess(const ServerRepo &)),
+ this, SLOT(onCreateSubrepoSuccess(const ServerRepo &)));
+ connect(data_mgr_, SIGNAL(createSubrepoFailed(const ApiError&)),
+ this, SLOT(onCreateSubrepoFailed(const ApiError&)));
+
+ connect(AutoUpdateManager::instance(), SIGNAL(fileUpdated(const QString&, const QString&)),
+ this, SLOT(onFileAutoUpdated(const QString&, const QString&)));
+
+ AccountManager* account_mgr = seafApplet->accountManager();
+ connect(account_mgr, SIGNAL(accountInfoUpdated(const Account&)), this,
+ SLOT(onAccountInfoUpdated()));
+
+ QTimer::singleShot(0, this, SLOT(init()));
+
+}
+
+FileBrowserDialog::~FileBrowserDialog()
+{
+ if (search_request_ != NULL)
+ search_request_->deleteLater();
+ delete data_mgr_notify_;
+}
+
+void FileBrowserDialog::init()
+{
+ enterPath(current_path_);
+}
+
+void FileBrowserDialog::createToolBar()
+{
+ toolbar_ = new QToolBar;
+ toolbar_->setObjectName("topBar");
+ toolbar_->setIconSize(QSize(kToolBarIconSize, kToolBarIconSize));
+
+ backward_button_ = new QToolButton(this);
+ backward_button_->setText(tr("Back"));
+ backward_button_->setObjectName("backwardButton");
+ backward_button_->setIcon(QIcon(":/images/filebrowser/backward.png"));
+ backward_button_->setEnabled(false);
+ backward_button_->setShortcut(QKeySequence::Back);
+ toolbar_->addWidget(backward_button_);
+ connect(backward_button_, SIGNAL(clicked()), this, SLOT(goBackward()));
+
+ forward_button_ = new QToolButton(this);
+ forward_button_->setText(tr("Forward"));
+ forward_button_->setObjectName("forwardButton");
+ forward_button_->setIcon(QIcon(":/images/filebrowser/forward.png"));
+ forward_button_->setEnabled(false);
+ forward_button_->setShortcut(QKeySequence::Forward);
+ toolbar_->addWidget(forward_button_);
+ connect(forward_button_, SIGNAL(clicked()), this, SLOT(goForward()));
+
+ // XX: not sure why, but we have to set the styles here, otherwise it won't
+ // work (if we write this in qt.css)
+ backward_button_->setStyleSheet("QToolButton { margin-right: -2px; }");
+ forward_button_->setStyleSheet("QToolButton { margin-left: -2px; margin-right: 10px;}");
+ toolbar_->setStyleSheet("QToolbar { spacing: 0px; }");
+
+ gohome_action_ = new QAction(tr("Home"), this);
+ gohome_action_->setIcon(QIcon(":images/filebrowser/home.png"));
+ connect(gohome_action_, SIGNAL(triggered()), this, SLOT(goHome()));
+ toolbar_->addAction(gohome_action_);
+ toolbar_->widgetForAction(gohome_action_)->setObjectName("goHomeButton");
+
+ path_navigator_ = new QButtonGroup(this);
+ connect(path_navigator_, SIGNAL(buttonClicked(int)),
+ this, SLOT(onNavigatorClick(int)));
+
+ search_toolbar_ = new QToolBar;
+ search_toolbar_->setObjectName("topBar");
+ search_toolbar_->setIconSize(QSize(kToolBarIconSize, kToolBarIconSize));
+ search_toolbar_->setFixedWidth(kSearchBarWidth);
+ search_toolbar_->setStyleSheet("QToolbar { spacing: 0px; }");
+
+ search_bar_ = new SearchBar;
+ search_bar_->setPlaceholderText(tr("Search files"));
+ search_toolbar_->addWidget(search_bar_);
+ connect(search_bar_, SIGNAL(textChanged(const QString&)),
+ this, SLOT(doSearch(const QString&)));
+ if (!account_.isPro()) {
+ search_toolbar_->setVisible(false);
+ }
+}
+
+void FileBrowserDialog::createStatusBar()
+{
+ status_bar_ = new QWidget;
+ status_bar_->setObjectName("statusBar");
+
+ status_layout_ = new QHBoxLayout(status_bar_);
+ status_layout_->setContentsMargins(0, 0, 0, 0);
+
+ // Submenu
+ upload_menu_ = new QMenu;
+ connect(upload_menu_, SIGNAL(aboutToShow()), this, SLOT(fixUploadButtonHighlightStyle()));
+ connect(upload_menu_, SIGNAL(aboutToHide()), this, SLOT(fixUploadButtonNonHighlightStyle()));
+
+ // Submenu's Action 1: Upload File
+ upload_file_action_ = new QAction(tr("Upload files"), upload_menu_);
+ connect(upload_file_action_, SIGNAL(triggered()), this, SLOT(chooseFileToUpload()));
+ upload_menu_->addAction(upload_file_action_);
+
+ upload_directory_action_ = new QAction(tr("Upload a directory"), upload_menu_);
+ connect(upload_directory_action_, SIGNAL(triggered()), this, SLOT(chooseDirectoryToUpload()));
+ upload_menu_->addAction(upload_directory_action_);
+
+ // Submenu's Action 3: Make a new directory
+ mkdir_action_ = new QAction(tr("Create a folder"), upload_menu_);
+ connect(mkdir_action_, SIGNAL(triggered()), this, SLOT(onMkdirButtonClicked()));
+ upload_menu_->addAction(mkdir_action_);
+
+ // Action to trigger Submenu
+ upload_button_ = new QToolButton;
+ upload_button_->setObjectName("uploadButton");
+ upload_button_->setToolTip(tr("Upload files"));
+ upload_button_->setIcon(QIcon(":/images/filebrowser/add.png"));
+ upload_button_->setIconSize(QSize(kStatusBarIconSize, kStatusBarIconSize));
+ upload_button_->installEventFilter(this);
+ connect(upload_button_, SIGNAL(clicked()), this, SLOT(uploadFileOrMkdir()));
+ status_layout_->addWidget(upload_button_);
+
+ if (current_readonly_) {
+ upload_button_->setEnabled(false);
+ upload_button_->setToolTip(tr("You don't have permission to upload files to this library"));
+ }
+
+ details_label_ = new QLabel;
+ details_label_->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
+ details_label_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ status_layout_->addWidget(details_label_);
+
+ refresh_button_ = new QToolButton;
+ refresh_button_->setObjectName("refreshButton");
+ refresh_button_->setToolTip(tr("Refresh"));
+ refresh_button_->setIcon(QIcon(":/images/filebrowser/refresh-gray.png"));
+ refresh_button_->setIconSize(QSize(kStatusBarIconSize, kStatusBarIconSize));
+ refresh_button_->installEventFilter(this);
+ connect(refresh_button_, SIGNAL(clicked()), this, SLOT(onRefresh()));
+ status_layout_->addWidget(refresh_button_);
+}
+
+void FileBrowserDialog::createFileTable()
+{
+ loading_view_ = new LoadingView;
+ table_view_ = new FileTableView(this);
+ table_model_ = new FileTableModel(this);
+ table_view_->setModel(table_model_);
+ table_view_->setColumnWidth(0,260);
+ table_view_->setColumnWidth(1,165);
+ table_view_->setColumnWidth(2,95);
+}
+
+bool FileBrowserDialog::handleDragDropEvent(QObject *obj, QEvent *event)
+{
+ if (event->type() == QEvent::DragEnter) {
+ QDragEnterEvent* ev = (QDragEnterEvent*)event;
+ // only handle external source currently
+ if(ev->source() != NULL)
+ return false;
+ // Otherwise it might be a MoveAction which is unacceptable
+ ev->setDropAction(Qt::CopyAction);
+ // trivial check
+ if(ev->mimeData()->hasFormat("text/uri-list"))
+ ev->accept();
+ return true;
+ }
+ else if (event->type() == QEvent::Drop) {
+ QDropEvent* ev = (QDropEvent*)event;
+ // only handle external source currently
+ if(ev->source() != NULL)
+ return false;
+
+ QList<QUrl> urls = ev->mimeData()->urls();
+
+ if(urls.isEmpty())
+ return false;
+
+ QStringList paths;
+ Q_FOREACH(const QUrl& url, urls)
+ {
+ QString path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+ path = utils::mac::fix_file_id_url(path);
+#endif
+ if(path.isEmpty())
+ continue;
+ paths.push_back(path);
+ }
+
+ ev->accept();
+
+ if (current_readonly_) {
+ seafApplet->warningBox(tr("You do not have permission to upload to this folder"), this);
+ } else {
+ uploadOrUpdateMutipleFile(paths);
+ }
+ return true;
+ }
+ else {
+ return QObject::eventFilter(obj, event);
+ }
+}
+
+bool FileBrowserDialog::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == upload_button_) {
+ // Sometimes the upload menu is dismissed, the upload button style won't
+ // change, and we need to handle it manually here as well as in the
+ // aboutToHide signal of the upload_meu. This might be a qt bug.
+ if (event->type() == QEvent::Enter) {
+ fixUploadButtonHighlightStyle();
+ return true;
+ } else if (event->type() == QEvent::Leave) {
+ fixUploadButtonNonHighlightStyle();
+ return true;
+ }
+ } else if (obj == refresh_button_) {
+ if (event->type() == QEvent::Enter) {
+ refresh_button_->setStyleSheet("FileBrowserDialog QToolButton#refreshButton {"
+ "background: #DFDFDF; padding: 3px;"
+ "margin-right: 12px; border-radius: 2px;}");
+ return true;
+ } else if (event->type() == QEvent::Leave) {
+ refresh_button_->setStyleSheet("FileBrowserDialog QToolButton#refreshButton {"
+ "background: #F5F5F7; padding: 0px;"
+ "margin-right: 15px;}");
+ return true;
+ }
+ } else if (obj == stack_) {
+ if (stack_->currentIndex() == INDEX_EMPTY_VIEW ||
+ stack_->currentIndex() == INDEX_TABLE_VIEW) {
+ return handleDragDropEvent(obj, event);
+ }
+ }
+
+ return QObject::eventFilter(obj, event);
+}
+
+void FileBrowserDialog::onRefresh()
+{
+ if (!seafApplet->accountManager()->currentAccount().isValid()) {
+ stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+ return;
+ }
+ if (!search_bar_->text().isEmpty()) {
+ search_text_last_modified_ = 1;
+ doRealSearch();
+ } else {
+ forceRefresh();
+ }
+}
+
+void FileBrowserDialog::forceRefresh()
+{
+ fetchDirents(true);
+}
+
+void FileBrowserDialog::fetchDirents()
+{
+ fetchDirents(false);
+}
+
+void FileBrowserDialog::updateFileCount()
+{
+ int row_count = 0;
+ if (stack_->currentIndex() == INDEX_TABLE_VIEW)
+ row_count = table_model_->rowCount();
+ if (stack_->currentIndex() == INDEX_SEARCH_VIEW)
+ row_count = search_model_->rowCount();
+
+ details_label_->setText(tr("%1 items").arg(row_count));
+}
+
+void FileBrowserDialog::fetchDirents(bool force_refresh)
+{
+ if (!has_password_dialog_ && repo_.encrypted && !data_mgr_->isRepoPasswordSet(repo_.id)) {
+ has_password_dialog_ = true;
+ SetRepoPasswordDialog password_dialog(repo_, this);
+ if (password_dialog.exec() != QDialog::Accepted) {
+ reject();
+ return;
+ } else {
+ has_password_dialog_ = false;
+ data_mgr_->setRepoPasswordSet(repo_.id, password_dialog.password());
+ }
+ }
+
+ if (!force_refresh) {
+ QList<SeafDirent> dirents;
+ if (data_mgr_->getDirents(repo_.id, current_path_, &dirents, ¤t_readonly_)) {
+ updateTable(dirents);
+ return;
+ }
+ }
+
+ showLoading();
+ data_mgr_->getDirentsFromServer(repo_.id, current_path_);
+}
+
+void FileBrowserDialog::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents)
+{
+ current_readonly_ = current_readonly;
+ updateTable(dirents);
+}
+
+void FileBrowserDialog::onGetDirentsFailed(const ApiError& error)
+{
+ if (error.httpErrorCode() == 401) {
+ stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+ } else {
+ stack_->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+ }
+}
+
+void FileBrowserDialog::onMkdirButtonClicked()
+{
+ QString name = seafApplet->getText(this, tr("Create a folder"),
+ tr("Folder name"));
+ name = name.trimmed();
+
+ if (name.isEmpty())
+ return;
+
+ // invalid name
+ if (name.contains("/")) {
+ seafApplet->warningBox(tr("Invalid folder name!"), this);
+ return;
+ }
+
+ if (findConflict(name, table_model_->dirents())) {
+ seafApplet->warningBox(
+ tr("The name \"%1\" is already taken.").arg(name), this);
+ return;
+ }
+
+ createDirectory(name);
+}
+
+void FileBrowserDialog::createLoadingFailedView()
+{
+ loading_failed_view_ = new QLabel;
+ loading_failed_view_->setObjectName(kLoadingFailedLabelName);
+ QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+ QString label_text = tr("Failed to get files information<br/>"
+ "Please %1").arg(link);
+ loading_failed_view_->setText(label_text);
+ loading_failed_view_->setAlignment(Qt::AlignCenter);
+
+ connect(loading_failed_view_, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(onRefresh()));
+}
+
+void FileBrowserDialog::createEmptyView()
+{
+ empty_view_ = new QLabel(this);
+ empty_view_->setText(tr("This folder is empty."));
+ empty_view_->setAlignment(Qt::AlignCenter);
+ empty_view_->setStyleSheet("background-color: white;");
+}
+
+void FileBrowserDialog::onDirentClicked(const SeafDirent& dirent)
+{
+ if (dirent.isDir()) {
+ onDirClicked(dirent);
+ } else {
+ onFileClicked(dirent);
+ }
+}
+
+void FileBrowserDialog::onDirentSaveAs(const QList<const SeafDirent*>& dirents)
+{
+ static QDir download_dir(defaultDownloadDir());
+ if (dirents.isEmpty())
+ return;
+ if (!download_dir.exists())
+ download_dir = QDir::home();
+
+ // handle when we have only one file
+ if (dirents.size() == 1) {
+ const SeafDirent &dirent = *dirents.front();
+ QString local_path = QFileDialog::getSaveFileName(this, tr("Enter name of file to save to..."), download_dir.filePath(dirent.name));
+ if (local_path.isEmpty())
+ return;
+ download_dir = QFileInfo(local_path).dir();
+ if (QFileInfo(local_path).exists()) {
+ // it is asked by the QFileDialog::getSaveFileName if overwrite the file
+ if (!QFile::remove(local_path)) {
+ seafApplet->warningBox(tr("Unable to remove file \"%1\""), this);
+ return;
+ }
+ }
+ FileDownloadTask *task = data_mgr_->createSaveAsTask(repo_.id, ::pathJoin(current_path_, dirent.name), local_path);
+ connect(task, SIGNAL(finished(bool)), this, SLOT(onDownloadFinished(bool)));
+ return;
+ }
+
+ QString local_dir = QFileDialog::getExistingDirectory(this, tr("Enter the path of the folder you want to save to..."), download_dir.path());
+ if (local_dir.isEmpty())
+ return;
+ download_dir = local_dir;
+ //
+ // scan for existing files and folders
+ // then begin downloading
+ //
+ Q_FOREACH(const SeafDirent* dirent, dirents) {
+ QString local_path = ::pathJoin(local_dir, dirent->name);
+ if (QFileInfo(local_path).exists()) {
+ if (!seafApplet->yesOrNoBox(tr("Do you want to overwrite the existing file \"%1\"?").arg(dirent->name))) {
+ return;
+ }
+ if (!QFile::remove(local_path)) {
+ seafApplet->warningBox(tr("Unable to remove file \"%1\""), this);
+ return;
+ }
+ }
+ // get them to be downloaded
+ FileDownloadTask *task = data_mgr_->createSaveAsTask(repo_.id, ::pathJoin(current_path_, dirent->name), local_path);
+ connect(task, SIGNAL(finished(bool)), this, SLOT(onDownloadFinished(bool)));
+ }
+}
+
+void FileBrowserDialog::showLoading()
+{
+ forward_button_->setEnabled(false);
+ backward_button_->setEnabled(false);
+ upload_button_->setEnabled(false);
+ gohome_action_->setEnabled(false);
+ stack_->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void FileBrowserDialog::onDirClicked(const SeafDirent& dir)
+{
+ const QString& path = ::pathJoin(current_path_, dir.name);
+ backward_history_.push(current_path_);
+ forward_history_.clear();
+ enterPath(path);
+}
+
+void FileBrowserDialog::enterPath(const QString& path)
+{
+ // printf ("enter path %s\n", toCStr(path));
+ current_path_ = path;
+ // use QUrl::toPercentEncoding if need
+ fetchDirents();
+
+ // QHash<QString, AutoUpdateManager::FileStatus> uploads =
+ // AutoUpdateManager::instance()->getFileStatusForDirectory(
+ // account_.getSignature(), repo_.id, path);
+ // if (uploads.empty()) {
+ // printf("no uploads for dir %s\n", toCStr(path));
+ // }
+ // foreach(const QString& key, uploads.keys()) {
+ // printf("auto upload status: file=\"%s\", uploading=%d\n", toCStr(key), uploads[key]);
+ // }
+
+ // current_path should be guaranteed safe to split!
+ current_lpath_ = current_path_.split('/');
+ // if the last element is empty (i.e. current_path_ ends with an extra "/"),
+ // remove it
+ if(current_lpath_.last().isEmpty())
+ current_lpath_.pop_back();
+
+ // remove all old buttons for navigator except the root
+ QList<QAbstractButton *> buttons = path_navigator_->buttons();
+ Q_FOREACH(QAbstractButton *button, buttons)
+ {
+ path_navigator_->removeButton(button);
+ delete button;
+ }
+ Q_FOREACH(QLabel *label, path_navigator_separators_)
+ {
+ delete label;
+ }
+ path_navigator_separators_.clear();
+
+ gohome_action_->setEnabled(path != "/");
+
+ // root is special
+ if (path == "/") {
+ QLabel *root = new QLabel(repo_.name);
+ toolbar_->addWidget(root);
+ path_navigator_separators_.push_back(root);
+ } else {
+ QPushButton *root = new QPushButton(repo_.name);
+ root->setObjectName("homeButton");
+ root->setFlat(true);
+ root->setCursor(Qt::PointingHandCursor);
+ toolbar_->addWidget(root);
+ path_navigator_->addButton(root, 0);
+
+ // add new buttons for navigator except the root
+ for(int i = 1; i < current_lpath_.size(); i++) {
+ QLabel *separator = new QLabel("/");
+ separator->setBaseSize(4, 7);
+ separator->setPixmap(QIcon(":/images/filebrowser/path-separator.png").pixmap(10));
+ path_navigator_separators_.push_back(separator);
+ toolbar_->addWidget(separator);
+ if (i != current_lpath_.size() - 1) {
+ QPushButton* button = new QPushButton(current_lpath_[i]);
+ button->setFlat(true);
+ button->setCursor(Qt::PointingHandCursor);
+ path_navigator_->addButton(button, i);
+ toolbar_->addWidget(button);
+ } else {
+ QLabel *separator = new QLabel(current_lpath_[i]);
+ toolbar_->addWidget(separator);
+ path_navigator_separators_.push_back(separator);
+ }
+ }
+ }
+}
+
+void FileBrowserDialog::onFileClicked(const SeafDirent& file)
+{
+ QString fpath = ::pathJoin(current_path_, file.name);
+
+ LocalRepo repo;
+ if (seafApplet->rpcClient()->getLocalRepo(repo_.id, &repo) == 0) {
+ QString synced_path = ::pathJoin(repo.worktree, fpath);
+ if (!QFileInfo(synced_path).exists()) {
+ seafApplet->warningBox(tr("File \"%1\" haven't been synced").arg(file.name));
+ return;
+ }
+ openFile(synced_path);
+ return;
+ }
+ QString cached_file = data_mgr_->getLocalCachedFile(repo_.id, fpath, file.id);
+ qDebug("cached_file is %s", cached_file.toUtf8().data());
+ if (!cached_file.isEmpty() && QFileInfo(cached_file).exists()) {
+ // double-checked the watch, since it might fails sometime
+ AutoUpdateManager::instance()->watchCachedFile(account_, repo_.id, fpath);
+ openFile(cached_file);
+ return;
+ } else {
+ if (TransferManager::instance()->getDownloadTask(repo_.id, fpath)) {
+ return;
+ }
+ AutoUpdateManager::instance()->removeWatch(
+ DataManager::getLocalCacheFilePath(repo_.id, fpath));
+ downloadFile(fpath);
+ }
+}
+
+void FileBrowserDialog::createDirectory(const QString &name)
+{
+ data_mgr_->createDirectory(repo_.id, ::pathJoin(current_path_, name));
+}
+
+void FileBrowserDialog::downloadFile(const QString& path)
+{
+ qDebug("begin to downloadfile is %s", path.toUtf8().data());
+ FileDownloadTask *task = data_mgr_->createDownloadTask(repo_.id, path);
+ connect(task, SIGNAL(finished(bool)), this, SLOT(onDownloadFinished(bool)));
+}
+
+void FileBrowserDialog::onGetDirentReupload(const SeafDirent& dirent)
+{
+ QString path = ::pathJoin(current_path_, dirent.name);
+ QString local_path = DataManager::getLocalCacheFilePath(repo_.id, path);
+ AutoUpdateManager::instance()->uploadFile(local_path);
+}
+
+void FileBrowserDialog::uploadFile(const QString& path, const QString& name,
+ bool overwrite)
+{
+ FileUploadTask *task =
+ data_mgr_->createUploadTask(repo_.id, current_path_, path, name, overwrite);
+ connect(task, SIGNAL(finished(bool)), this, SLOT(onUploadFinished(bool)));
+ FileBrowserProgressDialog *dialog = new FileBrowserProgressDialog(task, this);
+ task->start();
+
+ // set dialog attributes
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->setWindowModality(Qt::NonModal);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void FileBrowserDialog::uploadMultipleFile(const QStringList& names,
+ bool overwrite)
+{
+ if (names.empty())
+ return;
+ QString local_path;
+ QStringList fnames;
+ Q_FOREACH(const QString &name, names) {
+ const QFileInfo file = name;
+ if (file.isDir()) {
+ // a dir
+ uploadOrUpdateFile(name);
+ } else {
+ // a file
+ if (local_path.isEmpty()) {
+ local_path = file.path();
+ fnames.push_back(file.fileName());
+ } else if (file.path() == local_path) {
+ fnames.push_back(file.fileName());
+ } else {
+ qWarning(
+ "upload multiple files: ignore file %s because it's not in "
+ "the same directory",
+ toCStr(file.absoluteFilePath()));
+ }
+ }
+ }
+
+ if (fnames.empty()) {
+ return;
+ }
+
+ FileUploadTask *task =
+ data_mgr_->createUploadMultipleTask(repo_.id, current_path_, local_path, fnames,
+ overwrite);
+ connect(task, SIGNAL(finished(bool)), this, SLOT(onUploadFinished(bool)));
+ FileBrowserProgressDialog *dialog = new FileBrowserProgressDialog(task, this);
+ task->start();
+
+ // set dialog attributes
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->setWindowModality(Qt::NonModal);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void FileBrowserDialog::uploadFileOrMkdir()
+{
+ // the menu shows in the right-down corner
+ upload_menu_->exec(upload_button_->mapToGlobal(
+ QPoint(upload_button_->width()-2, upload_button_->height()/2)));
+}
+
+void FileBrowserDialog::uploadOrUpdateFile(const QString& path)
+{
+ const QString name = ::getBaseName(path);
+
+ // ignore the confirm procedure for uploading directory, which is non-sense
+ if (QFileInfo(path).isDir())
+ return uploadFile(path, name);
+
+ // prompt a dialog to confirm to overwrite the current file
+ if (findConflict(name, table_model_->dirents())) {
+ QMessageBox::StandardButton ret = seafApplet->yesNoCancelBox(
+ tr("File %1 already exists.<br/>"
+ "Do you like to overwrite it?<br/>"
+ "<small>(Choose No to upload using an alternative name).</small>").arg(name),
+ this,
+ QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel) {
+ return;
+ } else if (ret == QMessageBox::Yes) {
+ // overwrite the file
+ uploadFile(path, name, true);
+ return;
+ }
+ }
+
+ // in other cases, use upload
+ uploadFile(path, name);
+}
+
+void FileBrowserDialog::uploadOrUpdateMutipleFile(const QStringList &paths)
+{
+ if (paths.size() == 1)
+ uploadOrUpdateFile(paths.front());
+ else
+ uploadMultipleFile(paths);
+}
+
+void FileBrowserDialog::onDownloadFinished(bool success)
+{
+ FileDownloadTask *task = qobject_cast<FileDownloadTask *>(sender());
+ QString _error;
+ if (task == NULL)
+ return;
+ if (success) {
+ if (!task->isSaveAsTask())
+ openFile(task->localFilePath());
+ } else {
+ if (repo_.encrypted &&
+ setPasswordAndRetry(task)) {
+ return;
+ }
+
+ if (task->error() == FileNetworkTask::TaskCanceled)
+ return;
+
+ if (task->httpErrorCode() == 404) {
+ _error = tr("File does not exist");
+ } else if (task->httpErrorCode() == 401) {
+ _error = tr("Authorization expired");
+ } else {
+ _error = task->errorString();
+ }
+ QString msg = tr("Failed to download file: %1").arg(_error);
+ seafApplet->warningBox(msg, this);
+
+ if (task->httpErrorCode() == 401) {
+ stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+ }
+ }
+}
+
+void FileBrowserDialog::onUploadFinished(bool success)
+{
+ FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+ QString _error;
+ if (task == NULL)
+ return;
+
+ if (!success) {
+ if (repo_.encrypted &&
+ setPasswordAndRetry(task)) {
+ return;
+ }
+
+ // always force a refresh for uploading directory
+ if (qobject_cast<FileUploadDirectoryTask*>(sender()))
+ forceRefresh();
+
+ if (task->error() == FileNetworkTask::TaskCanceled)
+ return;
+
+ if (task->httpErrorCode() == 403) {
+ _error = tr("Permission Error!");
+ } else if (task->httpErrorCode() == 404) {
+ _error = tr("Library/Folder not found.");
+ } else if (task->httpErrorCode() == 401) {
+ _error = tr("Authorization expired");
+ } else {
+ _error = task->errorString();
+ }
+ QString msg = tr("Failed to upload file %1: %2").arg(task->failedPath()).arg(_error);
+ qWarning("failed to upload %s",toCStr(QFileInfo(task->failedPath()).fileName()));
+ seafApplet->warningBox(msg, this);
+ if (task->httpErrorCode() == 401) {
+ stack_->setCurrentIndex(INDEX_RELOGIN_VIEW);
+ }
+ return;
+ }
+
+ QString local_path = task->localFilePath();
+ QStringList names;
+
+ // Upload Directory Task
+ if (qobject_cast<FileUploadDirectoryTask *>(sender())) {
+ const SeafDirent dir = SeafDirent::dir(task->name());
+ // TODO: insert the Item prior to the item where uploading occurs
+ table_model_->insertItem(0, dir);
+ updateFileCount();
+ return;
+ }
+
+ // Upload Multiple Task
+ FileUploadMultipleTask *multi_task = qobject_cast<FileUploadMultipleTask *>(sender());
+
+ if (multi_task == NULL) {
+ names.push_back(task->name());
+ local_path = QFileInfo(local_path).absolutePath();
+ } else {
+ names = multi_task->successfulNames();
+ local_path = QFileInfo(local_path).absoluteFilePath();
+ }
+
+ // require a forceRefresh if conflicting filename found
+ Q_FOREACH(const QString &name, names)
+ {
+ if (findConflict(name, table_model_->dirents())) {
+ forceRefresh();
+ return;
+ }
+ }
+
+ // add the items to tableview
+ Q_FOREACH(const QString &name, names) {
+ const QFileInfo file = QDir(local_path).filePath(name);
+ const SeafDirent dirent = SeafDirent::file(name, static_cast<quint64>(file.size()));
+ if (task->useUpload())
+ table_model_->appendItem(dirent);
+ else
+ table_model_->replaceItem(name, dirent);
+ }
+
+ if (stack_->currentIndex() == INDEX_EMPTY_VIEW) {
+ forceRefresh();
+ }
+
+ updateFileCount();
+}
+
+bool FileBrowserDialog::setPasswordAndRetry(FileNetworkTask *task)
+{
+ if (task->httpErrorCode() == 400) {
+ if (has_password_dialog_) {
+ return true;
+ }
+ has_password_dialog_ = true;
+ SetRepoPasswordDialog password_dialog(repo_, this);
+ if (password_dialog.exec() == QDialog::Accepted) {
+ if (task->type() == FileNetworkTask::Download)
+ downloadFile(task->path());
+ else
+ uploadOrUpdateFile(task->path());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void FileBrowserDialog::goForward()
+{
+ QString path;
+ if (!forward_history_.empty()) {
+ path = forward_history_.pop();
+ }
+ backward_history_.push(current_path_);
+ enterPath(path);
+}
+
+void FileBrowserDialog::goBackward()
+{
+ QString path;
+ if (!backward_history_.empty()) {
+ path = backward_history_.pop();
+ }
+ forward_history_.push(current_path_);
+ enterPath(path);
+}
+
+void FileBrowserDialog::goHome()
+{
+ if (current_path_ == "/") {
+ return;
+ }
+ backward_history_.push(current_path_);
+ forward_history_.clear();
+ enterPath("/");
+}
+
+void FileBrowserDialog::updateTable(const QList<SeafDirent>& dirents)
+{
+ if (dirents.isEmpty()) {
+ table_model_->setDirents(QList<SeafDirent>());
+ stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+ } else {
+ table_model_->setDirents(dirents);
+ stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+ }
+
+ if (!forward_history_.empty()) {
+ forward_button_->setEnabled(true);
+ } else {
+ forward_button_->setEnabled(false);
+ }
+ if (!backward_history_.empty()) {
+ backward_button_->setEnabled(true);
+ } else {
+ backward_button_->setEnabled(false);
+ }
+ if (!current_readonly_) {
+ upload_button_->setEnabled(true);
+ }
+ gohome_action_->setEnabled(current_path_ != "/");
+ updateFileCount();
+}
+
+void FileBrowserDialog::chooseFileToUpload()
+{
+ QStringList paths = QFileDialog::getOpenFileNames(this, tr("Select a file to upload"), QDir::homePath());
+ if (paths.empty())
+ return;
+ uploadOrUpdateMutipleFile(paths);
+}
+
+void FileBrowserDialog::chooseDirectoryToUpload()
+{
+ QString path = QFileDialog::getExistingDirectory(this, tr("Select a directory to upload"), QDir::homePath());
+ if (path.isEmpty())
+ return;
+ uploadOrUpdateFile(path);
+}
+
+void FileBrowserDialog::onNavigatorClick(int id)
+{
+ // calculate the path
+ QString path = "/";
+ for(int i = 1; i <= id; i++)
+ path += current_lpath_[i] + "/";
+
+ backward_history_.push(current_path_);
+ forward_history_.clear();
+ enterPath(path);
+}
+
+void FileBrowserDialog::onGetDirentLock(const SeafDirent& dirent)
+{
+ data_mgr_->lockFile(repo_.id, ::pathJoin(current_path_, dirent.name), !dirent.is_locked);
+}
+
+void FileBrowserDialog::onGetDirentRename(const SeafDirent& dirent,
+ QString new_name)
+{
+ if (new_name.isEmpty()) {
+ new_name = seafApplet->getText(this, tr("Rename"),
+ QObject::tr("Rename %1 to").arg(dirent.name),
+ QLineEdit::Normal,
+ dirent.name);
+ // trim the whites
+ new_name = new_name.trimmed();
+ // if cancelled or empty
+ if (new_name.isEmpty())
+ return;
+ // if no change
+ if (dirent.name == new_name)
+ return;
+ }
+ data_mgr_->renameDirent(repo_.id,
+ ::pathJoin(current_path_, dirent.name),
+ new_name,
+ dirent.isFile());
+}
+
+void FileBrowserDialog::onGetDirentRemove(const SeafDirent& dirent)
+{
+ // if (seafApplet->yesOrNoBox(dirent.isFile() ?
+ // tr("Do you really want to delete file \"%1\"?").arg(dirent.name) :
+ // tr("Do you really want to delete folder \"%1\"?").arg(dirent.name), this, false))
+ data_mgr_->removeDirent(repo_.id, pathJoin(current_path_, dirent.name),
+ dirent.isFile());
+}
+
+void FileBrowserDialog::onGetDirentRemove(const QList<const SeafDirent*> &dirents)
+{
+ if (!seafApplet->yesOrNoBox(tr("Do you really want to delete these items"), this, false))
+ return;
+
+ QStringList filenames;
+ foreach (const SeafDirent *dirent, dirents) {
+ filenames << dirent->name;
+ }
+ data_mgr_->removeDirents(repo_.id, current_path_, filenames);
+}
+
+void FileBrowserDialog::onGetDirentShare(const SeafDirent& dirent)
+{
+ data_mgr_->shareDirent(repo_.id,
+ ::pathJoin(current_path_, dirent.name),
+ dirent.isFile());
+}
+
+void FileBrowserDialog::onGetDirentShareToUserOrGroup(const SeafDirent& dirent,
+ bool to_group)
+{
+ PrivateShareDialog dialog(account_, repo_.id, repo_.name,
+ ::pathJoin(current_path_, dirent.name), to_group,
+ this);
+ dialog.exec();
+}
+
+void FileBrowserDialog::onGetDirentUploadLink(const SeafDirent& dirent) {
+ QString repo_id = repo_.id;
+ QString path = ::pathJoin(current_path_, dirent.name);
+ if (dirent.isDir())
+ path += "/";
+ GetUploadLinkRequest *req = new GetUploadLinkRequest(account_, repo_id, path);
+ connect(req, SIGNAL(success(const QString&)), this,
+ SLOT(onGetUploadLinkSuccess(const QString)));
+ connect(req, SIGNAL(failed(const ApiError&)), this,
+ SLOT(onGetUploadLinkFailed(const ApiError&)));
+
+ req->send();
+}
+
+void FileBrowserDialog::onGetUploadLinkSuccess(const QString& upload_link) {
+ SharedLinkDialog *dialog = new SharedLinkDialog(upload_link, NULL, false);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void FileBrowserDialog::onGetUploadLinkFailed(const ApiError&) {
+ GetUploadLinkRequest *req = qobject_cast<GetUploadLinkRequest *>(sender());
+ const QString file = ::getBaseName(req->path());
+ seafApplet->messageBox(tr("Failed to get upload link information for file \"%1\"").arg(file));
+ req->deleteLater();
+}
+void FileBrowserDialog::onGetDirentShareSeafile(const SeafDirent& dirent)
+{
+ QString repo_id = repo_.id;
+ QString email = account_.username;
+ QString path = ::pathJoin(current_path_, dirent.name);
+ if (dirent.isDir())
+ path += "/";
+ GetSmartLinkRequest *req = new GetSmartLinkRequest(account_, repo_id, path, dirent.isDir());
+ connect(req, SIGNAL(success(const QString&, const QString&)),
+ this, SLOT(onGetSmartLinkSuccess(const QString&, const QString&)));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetSmartLinkFailed(const ApiError&)));
+
+ req->send();
+}
+
+void FileBrowserDialog::onGetSmartLinkSuccess(const QString& smart_link, const QString& protocol_link)
+{
+ SeafileLinkDialog(smart_link, protocol_link, this).exec();
+}
+
+void FileBrowserDialog::onGetSmartLinkFailed(const ApiError& error)
+{
+ seafApplet->warningBox(tr("Failed to get link"));
+}
+
+void FileBrowserDialog::onDirectoryCreateSuccess(const QString &path)
+{
+ const QString name = QFileInfo(path).fileName();
+ // if no longer current level
+ if (::pathJoin(current_path_, name) != path)
+ return;
+ const SeafDirent dirent = SeafDirent::dir(name);
+ // TODO insert to the pos where the drop event triggered
+ table_model_->insertItem(0, dirent);
+ if (stack_->currentIndex() == INDEX_EMPTY_VIEW)
+ forceRefresh();
+
+ updateFileCount();
+}
+
+void FileBrowserDialog::onDirectoryCreateFailed(const ApiError&error)
+{
+ seafApplet->warningBox(tr("Create folder failed"), this);
+}
+
+void FileBrowserDialog::onFileLockSuccess(const QString& path, bool lock)
+{
+ const QString name = QFileInfo(path).fileName();
+ // if no longer current level
+ if (::pathJoin(current_path_, name) != path)
+ return;
+ const SeafDirent *old_dirent = NULL;
+ Q_FOREACH(const SeafDirent& dirent, table_model_->dirents())
+ {
+ if (dirent.name == name) {
+ old_dirent = &dirent;
+ break;
+ }
+ }
+ if (!old_dirent)
+ return;
+ SeafDirent new_dirent = *old_dirent;
+ new_dirent.is_locked = new_dirent.locked_by_me = lock;
+ new_dirent.lock_owner = account_.username;
+ new_dirent.lock_owner_name = account_.accountInfo.name;
+ table_model_->replaceItem(name, new_dirent);
+}
+
+void FileBrowserDialog::onFileLockFailed(const ApiError& error)
+{
+ seafApplet->warningBox(tr("Lock file failed"), this);
+}
+
+void FileBrowserDialog::onDirentRenameSuccess(const QString& path,
+ const QString& new_name)
+{
+ const QString name = QFileInfo(path).fileName();
+ // if no longer current level
+ if (::pathJoin(current_path_, name) != path)
+ return;
+ table_model_->renameItemNamed(name, new_name);
+}
+
+void FileBrowserDialog::onGetDirentUpdate(const SeafDirent& dirent)
+{
+ QString path = QFileDialog::getOpenFileName(this,
+ tr("Select a file to update %1").arg(dirent.name), QDir::homePath());
+ if (!path.isEmpty()) {
+ uploadFile(path, dirent.name, true);
+ }
+}
+
+void FileBrowserDialog::onDirentRenameFailed(const ApiError&error)
+{
+ seafApplet->warningBox(tr("Rename failed"), this);
+}
+
+void FileBrowserDialog::onDirentRemoveSuccess(const QString& path)
+{
+ const QString name = QFileInfo(path).fileName();
+ // if no longer current level
+ if (::pathJoin(current_path_, name) != path)
+ return;
+ table_model_->removeItemNamed(name);
+ updateFileCount();
+
+ if (table_model_->rowCount() == 0) {
+ stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+ }
+}
+
+void FileBrowserDialog::onDirentRemoveFailed(const ApiError&error)
+{
+ seafApplet->warningBox(tr("Remove failed"), this);
+}
+
+void FileBrowserDialog::onDirentsRemoveSuccess(const QString& parent_path,
+ const QStringList& filenames)
+{
+ // if no longer current level
+ if (current_path_ != parent_path)
+ return;
+ foreach (const QString& name, filenames) {
+ // printf("removed file: %s\n", name.toUtf8().data());
+ table_model_->removeItemNamed(name);
+ }
+ updateFileCount();
+
+ if (table_model_->rowCount() == 0) {
+ stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+ }
+}
+
+void FileBrowserDialog::onDirentsRemoveFailed(const ApiError&error)
+{
+ seafApplet->warningBox(tr("Remove failed"), this);
+}
+
+void FileBrowserDialog::onDirentShareSuccess(const QString &link)
+{
+ SharedLinkDialog(link, this).exec();
+}
+
+void FileBrowserDialog::onDirentShareFailed(const ApiError&error)
+{
+ seafApplet->warningBox(tr("Share failed"), this);
+}
+
+void FileBrowserDialog::onFileAutoUpdated(const QString& repo_id, const QString& path)
+{
+ if (repo_id == repo_.id && path == current_path_) {
+ forceRefresh();
+ }
+}
+
+void FileBrowserDialog::onCancelDownload(const SeafDirent& dirent)
+{
+ TransferManager::instance()->cancelDownload(repo_.id,
+ ::pathJoin(current_path_, dirent.name));
+}
+
+
+void FileBrowserDialog::done(int retval)
+{
+ emit aboutToClose();
+ QDialog::done(retval);
+}
+
+bool FileBrowserDialog::hasFilesToBePasted() {
+ return !file_names_to_be_pasted_.empty();
+}
+
+void FileBrowserDialog::setFilesToBePasted(bool is_copy, const QMap<QString, int> &file_names)
+{
+ is_copyed_when_pasted_ = is_copy;
+ dir_path_to_be_pasted_from_ = current_path_;
+ file_names_to_be_pasted_ = file_names;
+ repo_id_to_be_pasted_from_ = repo_.id;
+ account_to_be_pasted_from_ = account_;
+}
+
+void FileBrowserDialog::onGetDirentsPaste()
+{
+ if (repo_id_to_be_pasted_from_ == repo_.id) {
+ if (current_path_ == dir_path_to_be_pasted_from_) {
+ seafApplet->warningBox(tr("Cannot paste files from the same folder"), this);
+ return;
+ }
+
+ if (file_names_to_be_pasted_.isEmpty()) {
+ return;
+ }
+
+ // Paste /a/ into /a/b/ is not allowed
+ for (const QString& name : file_names_to_be_pasted_.keys()) {
+ const QString file_path_to_be_pasted =
+ appendTrailingSlash(::pathJoin(dir_path_to_be_pasted_from_, name));
+ if (appendTrailingSlash(current_path_).startsWith(file_path_to_be_pasted)) {
+ seafApplet->warningBox(tr("Cannot paste the folder to its subfolder"), this);
+ return;
+ }
+ }
+ }
+
+ if (is_copyed_when_pasted_)
+ data_mgr_->copyDirents(repo_id_to_be_pasted_from_,
+ dir_path_to_be_pasted_from_,
+ file_names_to_be_pasted_,
+ repo_.id,
+ current_path_);
+ else
+ data_mgr_->moveDirents(repo_id_to_be_pasted_from_,
+ dir_path_to_be_pasted_from_,
+ file_names_to_be_pasted_,
+ repo_.id,
+ current_path_);
+}
+
+void FileBrowserDialog::onDirentsCopySuccess()
+{
+ forceRefresh();
+}
+
+void FileBrowserDialog::onDirentsCopyFailed(const ApiError& error)
+{
+ seafApplet->warningBox(tr("Copy failed"), this);
+}
+
+void FileBrowserDialog::onDirentsMoveSuccess()
+{
+ file_names_to_be_pasted_.clear();
+ FileBrowserDialog *dialog =
+ FileBrowserManager::getInstance()->getDialog(account_to_be_pasted_from_, repo_id_to_be_pasted_from_);
+ if (dialog != NULL && dialog->current_path_ == dir_path_to_be_pasted_from_) {
+ dialog->forceRefresh();
+ }
+
+ msleep(500);
+ forceRefresh();
+}
+
+void FileBrowserDialog::onDirentsMoveFailed(const ApiError& error)
+{
+ seafApplet->warningBox(tr("Move failed"), this);
+}
+
+void FileBrowserDialog::onGetSyncSubdirectory(const QString &folder_name)
+{
+ data_mgr_->createSubrepo(folder_name, repo_.id, ::pathJoin(current_path_, folder_name));
+}
+
+void FileBrowserDialog::onDeleteLocalVersion(const SeafDirent &dirent)
+{
+ QString fpath = ::pathJoin(current_path_, dirent.name);
+ QString cached_file = data_mgr_->getLocalCachedFile(repo_.id, fpath, dirent.id);
+ if (!cached_file.isEmpty() && QFileInfo(cached_file).exists()) {
+ QFile::remove(cached_file);
+ return;
+ }
+}
+
+void FileBrowserDialog::onLocalVersionSaveAs(const SeafDirent &dirent)
+{
+ static QDir download_dir(defaultDownloadDir());
+ if (!download_dir.exists())
+ download_dir = QDir::home();
+
+ QString fpath = ::pathJoin(current_path_, dirent.name);
+ QString cached_file = data_mgr_->getLocalCachedFile(repo_.id, fpath, dirent.id);
+ if (!cached_file.isEmpty() && QFileInfo(cached_file).exists()) {
+ QString local_path = QFileDialog::getSaveFileName(this, tr("Enter name of file to save to..."), download_dir.filePath(dirent.name));
+ QFile::copy(cached_file, local_path);
+ return;
+ }
+}
+
+void FileBrowserDialog::onOpenLocalCacheFolder()
+{
+ QString folder =
+ ::pathJoin(data_mgr_->getRepoCacheFolder(repo_.id), current_path_);
+ if (!::createDirIfNotExists(folder)) {
+ seafApplet->warningBox(tr("Unable to create cache folder"), this);
+ return;
+ }
+ if (!QDesktopServices::openUrl(QUrl::fromLocalFile(folder)))
+ seafApplet->warningBox(tr("Unable to open cache folder"), this);
+}
+
+void FileBrowserDialog::onCreateSubrepoSuccess(const ServerRepo &repo)
+{
+ // if we have not synced before
+ bool has_local = false;
+ if (seafApplet->rpcClient()->hasLocalRepo(repo.id)) {
+ has_local = true;
+ } else {
+ // if we have not synced, do it
+ DownloadRepoDialog dialog(account_, repo,
+ repo.encrypted ? data_mgr_->repoPassword(repo_.id) : QString(), this);
+
+ has_local = dialog.exec() == QDialog::Accepted;
+ }
+
+ if (has_local)
+ RepoService::instance()->saveSyncedSubfolder(repo);
+}
+
+void FileBrowserDialog::onCreateSubrepoFailed(const ApiError&error)
+{
+ seafApplet->warningBox(tr("Create library failed!"), this);
+}
+
+void FileBrowserDialog::fixUploadButtonHighlightStyle()
+{
+ fixUploadButtonStyle(true);
+}
+
+void FileBrowserDialog::fixUploadButtonNonHighlightStyle()
+{
+ fixUploadButtonStyle(false);
+}
+
+void FileBrowserDialog::fixUploadButtonStyle(bool highlighted)
+{
+ if (highlighted) {
+ upload_button_->setStyleSheet("FileBrowserDialog QToolButton#uploadButton {"
+ "background: #DFDFDF; padding: 3px;"
+ "margin-left: 12px; border-radius: 2px;}");
+ } else {
+ // XX: underMouse() return true even if the upload button is not under mouse!
+ //
+ // if (upload_button_->underMouse()) {
+ // return;
+ // }
+ upload_button_->setStyleSheet("FileBrowserDialog QToolButton#uploadButton {"
+ "background: #F5F5F7; padding: 0px;"
+ "margin-left: 15px;}");
+ }
+}
+
+void FileBrowserDialog::onAccountInfoUpdated()
+{
+ forceRefresh();
+}
+
+void FileBrowserDialog::doSearch(const QString &keyword)
+{
+ // make it search utf-8 charcters
+ if (keyword.toUtf8().size() < 3) {
+ stack_->setCurrentIndex(INDEX_TABLE_VIEW);
+ updateFileCount();
+ return;
+ }
+
+ // save for doRealSearch
+ search_text_last_modified_ = QDateTime::currentMSecsSinceEpoch();
+}
+
+void FileBrowserDialog::doRealSearch()
+{
+ // not modified
+ if (search_text_last_modified_ == 0)
+ return;
+ // modified too fast
+ if (QDateTime::currentMSecsSinceEpoch() - search_text_last_modified_ <= 300)
+ return;
+
+ if (!account_.isValid())
+ return;
+
+ if (search_request_) {
+ // search_request_->abort();
+ search_request_->deleteLater();
+ search_request_ = NULL;
+ }
+
+ stack_->setCurrentIndex(INDEX_LOADING_VIEW);
+
+ search_request_ = new FileSearchRequest(account_, search_bar_->text(), kAllPage, kPerPageCount, repo_.id);
+ connect(search_request_, SIGNAL(success(const std::vector<FileSearchResult>&, bool, bool)),
+ this, SLOT(onSearchSuccess(const std::vector<FileSearchResult>&, bool, bool)));
+ connect(search_request_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onSearchFailed(const ApiError&)));
+
+ search_request_->send();
+
+ // reset
+ search_text_last_modified_ = 0;
+}
+
+void FileBrowserDialog::onSearchSuccess(const std::vector<FileSearchResult>& results,
+ bool is_loading_more,
+ bool has_more)
+{
+ search_model_->setSearchResult(results);
+ stack_->setCurrentIndex(INDEX_SEARCH_VIEW);
+ updateFileCount();
+}
+
+void FileBrowserDialog::onSearchFailed(const ApiError& error)
+{
+ stack_->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+}
+
+
+DataManagerNotify::DataManagerNotify(const QString &repo_id)
+ :repo_id_(repo_id)
+{
+ data_mgr_ = seafApplet->dataManager();
+ connect(data_mgr_, SIGNAL(getDirentsSuccess(bool, const QList<SeafDirent>&, const QString&)),
+ this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent>&, const QString&)));
+ connect(data_mgr_, SIGNAL(getDirentsFailed(const ApiError&, const QString&)),
+ this, SLOT(onGetDirentsFailed(const ApiError&, const QString&)));
+ connect(data_mgr_, SIGNAL(createDirectorySuccess(const QString&, const QString&)),
+ this, SLOT(onDirectoryCreateSuccess(const QString&, const QString&)));
+ connect(data_mgr_, SIGNAL(lockFileSuccess(const QString&, bool, const QString&)),
+ this, SLOT(onFileLockSuccess(const QString&, bool, const QString&)));
+ connect(data_mgr_, SIGNAL(renameDirentSuccess(const QString&, const QString&, const QString&)),
+ this, SLOT(onDirentRenameSuccess(const QString&, const QString&, const QString&)));
+ connect(data_mgr_, SIGNAL(removeDirentSuccess(const QString&, const QString&)),
+ this, SLOT(onDirentRemoveSuccess(const QString&, const QString&)));
+ connect(data_mgr_, SIGNAL(removeDirentsSuccess(const QString&, const QStringList&, const QString&)),
+ this, SLOT(onDirentsRemoveSuccess(const QString&, const QStringList&, const QString&)));
+ connect(data_mgr_, SIGNAL(shareDirentSuccess(const QString&, const QString&)),
+ this, SLOT(onDirentShareSuccess(const QString&, const QString&)));
+ connect(data_mgr_, SIGNAL(createSubrepoSuccess(const ServerRepo &, const QString&)),
+ this, SLOT(onCreateSubrepoSuccess(const ServerRepo &, const QString&)));
+ connect(data_mgr_, SIGNAL(copyDirentsSuccess(const QString&)),
+ this, SLOT(onDirentsCopySuccess(const QString&)));
+ connect(data_mgr_, SIGNAL(moveDirentsSuccess(const QString&)),
+ this, SLOT(onDirentsMoveSuccess(const QString&)));
+}
+
+void DataManagerNotify::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit getDirentsSuccess(current_readonly, dirents);
+ }
+}
+
+void DataManagerNotify::onGetDirentsFailed(const ApiError &error, const QString &repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit getDirentsFailed(error);
+ }
+}
+
+void DataManagerNotify::onDirectoryCreateSuccess(const QString &path, const QString &repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit createDirectorySuccess(path);
+ }
+}
+
+void DataManagerNotify::onFileLockSuccess(const QString &path, bool lock, const QString &repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit lockFileSuccess(path, lock);
+ }
+}
+
+void DataManagerNotify::onDirentRenameSuccess(const QString &path, const QString &new_name, const QString &repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit renameDirentSuccess(path, new_name);
+ }
+}
+
+void DataManagerNotify::onDirentRemoveSuccess(const QString &path, const QString &repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit removeDirentSuccess(path);
+ }
+}
+
+void DataManagerNotify::onDirentsRemoveSuccess(const QString &parent_path, const QStringList &filenames, const QString &repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit removeDirentsSuccess(parent_path, filenames);
+ }
+}
+
+void DataManagerNotify::onDirentShareSuccess(const QString &link, const QString &repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit shareDirentSuccess(link);
+ }
+}
+
+void DataManagerNotify::onCreateSubrepoSuccess(const ServerRepo &repo, const QString& repo_id)
+{
+ if (repo_id == repo_id_) {
+ emit createSubrepoSuccess(repo);
+ }
+}
+
+void DataManagerNotify::onDirentsCopySuccess(const QString& dst_repo_id)
+{
+ if (dst_repo_id == repo_id_) {
+ emit copyDirentsSuccess();
+ }
+}
+
+void DataManagerNotify::onDirentsMoveSuccess(const QString& dst_repo_id)
+{
+ if (dst_repo_id == repo_id_) {
+ emit moveDirentsSuccess();
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_DIALOG_H
+
+#include <QStack>
+#include <QDialog>
+
+#include "account.h"
+#include "api/server-repo.h"
+#include "file-browser-search-tab.h"
+#include "ui/search-bar.h"
+
+class QToolBar;
+class QToolButton;
+class QAction;
+class QStackedWidget;
+class QLineEdit;
+class QLabel;
+class QButtonGroup;
+class QMenu;
+class QAction;
+class QSizeGrip;
+class QHBoxLayout;
+
+class ApiError;
+class FileTableView;
+class FileTableModel;
+class SeafDirent;
+class GetDirentsRequest;
+class FileBrowserCache;
+class DataManager;
+class DataManagerNotify;
+class FileNetworkTask;
+class FileBrowserManager;
+
+class SearchBar;
+class FileBrowserSearchItemDelegate;
+class FileBrowserSearchView;
+class FileBrowserSearchModel;
+struct FileSearchResult;
+class FileSearchRequest;
+
+/**
+ * This dialog is used when the user clicks on a repo not synced yet.
+ *
+ * The user can browse the files of this repo. When he clicks on a file, the
+ * file would be downloaded to a temporary location. If the user modifies the
+ * downloaded file, the new version would be automatically uploaded to the
+ * server.
+ *
+ */
+class FileBrowserDialog : public QDialog
+ // public Ui::FileBrowserDialog
+{
+ Q_OBJECT
+ friend class FileBrowserManager;
+public:
+ FileBrowserDialog(const Account &account, const ServerRepo& repo,
+ const QString &path, QWidget *parent=0);
+ ~FileBrowserDialog();
+
+ // only accept path ends with "/"
+ void enterPath(const QString& path);
+ void onGetDirentReupload(const SeafDirent& dirent);
+ void onOpenLocalCacheFolder();
+
+ friend class FileTableView;
+ friend class FileTableModel;
+signals:
+ void aboutToClose();
+
+private slots:
+ void init();
+
+ void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents);
+ void onGetDirentsFailed(const ApiError& error);
+ void onMkdirButtonClicked();
+ void fetchDirents();
+ void onDirentClicked(const SeafDirent& dirent);
+ void onDirentSaveAs(const QList<const SeafDirent*>& dirents);
+ void onRefresh();
+ void goForward();
+ void goBackward();
+ void goHome();
+ void chooseFileToUpload();
+ void chooseDirectoryToUpload();
+ void onDownloadFinished(bool success);
+ void onUploadFinished(bool success);
+
+ // prompt a menu for user to choose a upload action
+ void uploadFileOrMkdir();
+
+ // prompt a dialog for user to choose whether upload or update
+ void uploadOrUpdateFile(const QString& path);
+ void uploadOrUpdateMutipleFile(const QStringList& paths);
+
+ void onNavigatorClick(int id);
+
+ void onGetDirentLock(const SeafDirent& dirent);
+ void onGetDirentRename(const SeafDirent& dirent, QString new_name = QString());
+ void onGetDirentRemove(const SeafDirent& dirent);
+ void onGetDirentRemove(const QList<const SeafDirent*> &dirents);
+ void onGetDirentShare(const SeafDirent& dirent);
+ void onGetDirentShareToUserOrGroup(const SeafDirent& dirent, bool to_group);
+ void onGetDirentShareSeafile(const SeafDirent& dirent);
+ void onGetDirentUploadLink(const SeafDirent& dirent);
+ void onGetUploadLinkSuccess(const QString& upload_link);
+ void onGetUploadLinkFailed(const ApiError&);
+ void onGetDirentUpdate(const SeafDirent& dirent);
+ void onGetDirentsPaste();
+ void onGetSyncSubdirectory(const QString &folder_name);
+ void onCancelDownload(const SeafDirent& dirent);
+
+ void onDeleteLocalVersion(const SeafDirent& dirent);
+ void onLocalVersionSaveAs(const SeafDirent& dirent);
+ void onDirectoryCreateSuccess(const QString& path);
+ void onDirectoryCreateFailed(const ApiError& error);
+ void onFileLockSuccess(const QString& path, bool lock);
+ void onFileLockFailed(const ApiError& error);
+ void onDirentRenameSuccess(const QString& path, const QString& new_name);
+ void onDirentRenameFailed(const ApiError& error);
+ void onDirentRemoveSuccess(const QString& path);
+ void onDirentRemoveFailed(const ApiError& error);
+
+ void onDirentsRemoveSuccess(const QString& parent_path,
+ const QStringList& filenames);
+ void onDirentsRemoveFailed(const ApiError& error);
+
+ void onDirentShareSuccess(const QString& link);
+ void onDirentShareFailed(const ApiError& error);
+
+ void onDirentsCopySuccess();
+ void onDirentsCopyFailed(const ApiError& error);
+ void onDirentsMoveSuccess();
+ void onDirentsMoveFailed(const ApiError& error);
+
+ void onCreateSubrepoSuccess(const ServerRepo& repo);
+ void onCreateSubrepoFailed(const ApiError& error);
+
+ void onFileAutoUpdated(const QString& repo_id, const QString& path);
+
+ void fixUploadButtonStyle(bool highlighted);
+ void fixUploadButtonNonHighlightStyle();
+ void fixUploadButtonHighlightStyle();
+
+ void onAccountInfoUpdated();
+
+ //search
+ void doSearch(const QString& keyword);
+ void doRealSearch();
+ void onSearchSuccess(const std::vector<FileSearchResult>& results,
+ bool is_loading_more,
+ bool has_more);
+ void onSearchFailed(const ApiError& error);
+
+ void onGetSmartLinkSuccess(const QString& smart_link, const QString& protocol_link);
+ void onGetSmartLinkFailed(const ApiError& error);
+private:
+ Q_DISABLE_COPY(FileBrowserDialog)
+
+ void done(int retval);
+ bool hasFilesToBePasted();
+ void setFilesToBePasted(bool is_copy, const QMap<QString ,int> &file_names);
+
+ void createToolBar();
+ void createStatusBar();
+ void createFileTable();
+ void createLoadingFailedView();
+ void createEmptyView();
+ void showLoading();
+ void updateTable(const QList<SeafDirent>& dirents);
+ void createDirectory(const QString &name);
+ void downloadFile(const QString& path);
+ void uploadFile(const QString& path, const QString& name,
+ bool overwrite = false);
+ void uploadMultipleFile(const QStringList& paths, bool overwrite = false);
+
+ void onDirClicked(const SeafDirent& dirent);
+ void onFileClicked(const SeafDirent& dirent);
+
+ void fetchDirents(bool force_refresh);
+
+ void updateFileCount();
+
+ void forceRefresh();
+
+ bool setPasswordAndRetry(FileNetworkTask *task);
+
+ bool eventFilter(QObject *obj, QEvent *event);
+ bool handleDragDropEvent(QObject *obj, QEvent *event);
+
+ const Account account_;
+ const ServerRepo repo_;
+
+ // current path
+ QString current_path_;
+ QStringList current_lpath_;
+ bool current_readonly_;
+ QStack<QString> forward_history_;
+ QStack<QString> backward_history_;
+
+ //search
+ QTimer *search_timer_;
+ FileSearchRequest *search_request_;
+ qint64 search_text_last_modified_;
+
+ // copy-paste related items between different instances of FileBrowserDialog
+ static QMap<QString, int> file_names_to_be_pasted_;
+ static QString dir_path_to_be_pasted_from_;
+ static QString repo_id_to_be_pasted_from_;
+ static Account account_to_be_pasted_from_;
+ static bool is_copyed_when_pasted_;
+
+ QLabel *brand_label_;
+ QPushButton *minimize_button_;
+ QPushButton *close_button_;
+ QPoint old_pos_;
+
+ // top toolbar
+ QToolBar *toolbar_;
+ QToolBar *search_toolbar_;
+ QToolButton *backward_button_;
+ QToolButton *forward_button_;
+ QButtonGroup *path_navigator_;
+ QList<QLabel*> path_navigator_separators_;
+ QAction *gohome_action_;
+
+ // status toolbar
+ QWidget *status_bar_;
+ QHBoxLayout *status_layout_;
+ QToolButton *upload_button_;
+ QMenu *upload_menu_;
+ QAction *upload_file_action_;
+ QAction *upload_directory_action_;
+ QAction *mkdir_action_;
+ QLabel *details_label_;
+ QToolButton *refresh_button_;
+
+ // others
+ QStackedWidget *stack_;
+ QWidget *loading_view_;
+ QLabel *loading_failed_view_;
+ QWidget *relogin_view_;
+ QLabel *empty_view_;
+ FileTableView *table_view_;
+ FileTableModel *table_model_;
+
+ SearchBar *search_bar_;
+ FileBrowserSearchItemDelegate *search_delegate_;
+ FileBrowserSearchView *search_view_;
+ FileBrowserSearchModel *search_model_;
+
+ DataManager *data_mgr_;
+ DataManagerNotify *data_mgr_notify_;
+
+ // Avoid showing multiple SetRepoPasswordDialog
+ bool has_password_dialog_;
+};
+
+class DataManagerNotify : public QObject {
+ Q_OBJECT
+public:
+ DataManagerNotify(const QString& repo_id);
+ ~DataManagerNotify(){};
+signals:
+ void getDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents);
+ void getDirentsFailed(const ApiError& error);
+ void createDirectorySuccess(const QString& path);
+ void lockFileSuccess(const QString& path, bool lock);
+ void renameDirentSuccess(const QString& path, const QString& new_name);
+ void removeDirentSuccess(const QString& path);
+ void removeDirentsSuccess(const QString& parent_path, const QStringList& filenames);
+ void shareDirentSuccess(const QString& link);
+ void createSubrepoSuccess(const ServerRepo &repo);
+ void copyDirentsSuccess();
+ void moveDirentsSuccess();
+
+private slots:
+ void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent>& dirents, const QString& repo_id);
+ void onGetDirentsFailed(const ApiError& error, const QString& repo_id);
+ void onDirectoryCreateSuccess(const QString& path, const QString& repo_id);
+ void onFileLockSuccess(const QString& path, bool lock, const QString& repo_id);
+ void onDirentRenameSuccess(const QString& path, const QString& new_name, const QString& repo_id);
+ void onDirentRemoveSuccess(const QString& path, const QString& repo_id);
+ void onDirentsRemoveSuccess(const QString& parent_path,
+ const QStringList& filenames,
+ const QString& repo_id);
+ void onDirentShareSuccess(const QString& link, const QString& repo_id);
+ void onCreateSubrepoSuccess(const ServerRepo& repo, const QString& repo_id);
+ void onDirentsCopySuccess(const QString& dst_repo_id);
+ void onDirentsMoveSuccess(const QString& dst_repo_id);
+
+private:
+ DataManager *data_mgr_;
+ QString repo_id_;
+
+};
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_DIALOG_H
--- /dev/null
+#include "file-browser-manager.h"
+
+#include <QApplication>
+#include <QDesktopWidget>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+
+#include "file-browser-dialog.h"
+
+namespace {
+}
+
+FileBrowserManager *FileBrowserManager::instance_ = NULL;
+
+FileBrowserManager::FileBrowserManager() : QObject()
+{
+ // We use the accountAboutToRelogin signal instead of the
+ // accountRequireRelogin signal because other components are already
+ // connected to the the latter and may prompt a re-login dialog which would
+ // delay the call to our slots.
+ connect(seafApplet->accountManager(),
+ SIGNAL(accountAboutToRelogin(const Account&)),
+ this,
+ SLOT(closeAllDialogByAccount(const Account&)));
+
+ connect(seafApplet->accountManager(), SIGNAL(beforeAccountSwitched()),
+ this, SLOT(closeAllDialogs()));
+}
+
+
+FileBrowserDialog *FileBrowserManager::openOrActivateDialog(const Account &account, const ServerRepo &repo, const QString &path)
+{
+ FileBrowserDialog *dialog = getDialog(account, repo.id);
+ QString fixed_path = path;
+ if (!fixed_path.startsWith("/")) {
+ fixed_path = "/" + fixed_path;
+ }
+ if (!fixed_path.endsWith("/")) {
+ fixed_path += "/";
+ }
+ if (dialog == NULL) {
+ dialog = new FileBrowserDialog(account, repo, fixed_path);
+ QRect screen = QApplication::desktop()->screenGeometry();
+ dialog->setAttribute(Qt::WA_DeleteOnClose, true);
+ dialog->show();
+ dialog->move(screen.center() - dialog->rect().center());
+ dialogs_.push_back(dialog);
+ connect(dialog, SIGNAL(aboutToClose()), this, SLOT(onAboutToClose()));
+ } else if (!path.isEmpty()) {
+ dialog->enterPath(fixed_path);
+ }
+ dialog->raise();
+ dialog->activateWindow();
+ return dialog;
+}
+
+FileBrowserDialog *FileBrowserManager::getDialog(const Account &account, const QString &repo_id)
+{
+ // printf ("Get dialog: current %u CFB\n", dialogs_.size());
+ // search and find if dialog registered
+ for (int i = 0; i < dialogs_.size() ; i++)
+ if (dialogs_[i]->account_ == account &&
+ dialogs_[i]->repo_.id == repo_id) {
+ return dialogs_[i];
+ }
+ // not found
+ return NULL;
+}
+
+void FileBrowserManager::closeAllDialogByAccount(const Account& account)
+{
+ // printf ("closeAllDialogByAccount is called\n");
+
+ // Close all dialogs for the given account, e.g. when logging out or
+ // deleteing an account.
+
+ // Note: DO NOT remove close the dialog while iterating the dialogs list,
+ // because close the dialog would make it removed from the list (through the
+ // onAboutToClose signal). Instead we first collect the matched dialogs into
+ // a temporary list, then close them one by one.
+ QList<FileBrowserDialog *> dialogs_for_account;
+ foreach (FileBrowserDialog *dialog, dialogs_)
+ {
+ if (dialog->account_ == account) {
+ dialogs_for_account.push_back(dialog);
+ }
+ }
+
+ foreach (FileBrowserDialog *dialog, dialogs_for_account)
+ {
+ dialog->close();
+ // printf ("closed one CFB\n");
+ }
+}
+
+void FileBrowserManager::onAboutToClose()
+{
+ // printf ("got onAboutToClose\n");
+ FileBrowserDialog *dialog = qobject_cast<FileBrowserDialog*>(sender());
+ if (!dialog)
+ return;
+ dialogs_.removeOne(dialog);
+}
+
+void FileBrowserManager::closeAllDialogs()
+{
+ QList<FileBrowserDialog *> dialogs_for_account;
+ foreach (FileBrowserDialog *dialog, dialogs_)
+ {
+ dialogs_for_account.push_back(dialog);
+ }
+
+ foreach (FileBrowserDialog *dialog, dialogs_for_account)
+ {
+ dialog->close();
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_MANAGER_H
+#include <QObject>
+#include <QList>
+#include "api/server-repo.h"
+#include "account.h"
+
+class FileBrowserDialog;
+
+class FileBrowserManager : public QObject {
+ Q_OBJECT
+public:
+ static FileBrowserManager* getInstance() {
+ if (!instance_) {
+ static FileBrowserManager instance;
+ instance_ = &instance;
+ }
+ return instance_;
+ }
+
+ FileBrowserDialog *openOrActivateDialog(const Account &account, const ServerRepo &repo, const QString &path = "/");
+
+ FileBrowserDialog *getDialog(const Account &account, const QString &repo_id);
+
+public slots:
+ void closeAllDialogByAccount(const Account &account);
+
+private slots:
+ void onAboutToClose();
+ void closeAllDialogs();
+
+private:
+ FileBrowserManager(const FileBrowserManager*); // DELETED
+ FileBrowserManager& operator=(const FileBrowserManager*); // DELETED
+
+ FileBrowserManager();
+ static FileBrowserManager *instance_;
+ QList<FileBrowserDialog*> dialogs_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_MANAGER_H
--- /dev/null
+#include "file-browser-requests.h"
+
+#include <jansson.h>
+#include <QtNetwork>
+#include <QScopedPointer>
+#include <QMapIterator>
+
+#include "account.h"
+#include "api/api-error.h"
+#include "seaf-dirent.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "src/open-local-helper.h"
+#include "utils/json-utils.h"
+#include "seafile-applet.h"
+
+namespace {
+
+const char kGetDirentsUrl[] = "api2/repos/%1/dir/";
+const char kGetFilesUrl[] = "api2/repos/%1/file/";
+const char kGetFileSharedLinkUrl[] = "api2/repos/%1/file/shared-link/";
+const char kGetFileUploadUrl[] = "api2/repos/%1/upload-link/";
+const char kGetFileUpdateUrl[] = "api2/repos/%1/update-link/";
+const char kGetStarredFilesUrl[] = "api2/starredfiles/";
+const char kQueryAsyncOperationProgressUrl[] = "api/v2.1/query-copy-move-progress/";
+const char kCopyMoveSingleItemUrl[] = "api/v2.1/copy-move-task/";
+const char kFileOperationCopy[] = "api2/repos/%1/fileops/copy/";
+const char kAsyncCopyMultipleItems[] = "api/v2.1/repos/async-batch-copy-item/";
+const char kAsyncMoveMultipleItems[] = "api/v2.1/repos/async-batch-move-item/";
+const char kFileOperationMove[] = "api2/repos/%1/fileops/move/";
+const char kRemoveDirentsURL[] = "api2/repos/%1/fileops/delete/";
+const char kGetFileUploadedBytesUrl[] = "api/v2.1/repos/%1/file-uploaded-bytes/";
+const char kGetSmartLink[] = "api/v2.1/smart-link/";
+const char kGetUploadLinkUrl[] = "api/v2.1/upload-links/";
+
+//const char kGetFileFromRevisionUrl[] = "api2/repos/%1/file/revision/";
+//const char kGetFileDetailUrl[] = "api2/repos/%1/file/detail/";
+//const char kGetFileHistoryUrl[] = "api2/repos/%1/file/history/";
+
+QByteArray assembleJsonReq(const QString& repo_id, const QString& src_dir_path,
+ const QStringList& src_file_names, const QString& dst_repo_id,
+ const QString& dst_dir_path)
+{
+ QJsonObject json_obj;
+ QJsonArray dirents_array;
+ json_obj.insert("src_repo_id", repo_id);
+ json_obj.insert("src_parent_dir", src_dir_path);
+ Q_FOREACH(const QString & src_file_name, src_file_names) {
+ dirents_array.append(src_file_name);
+ }
+ json_obj.insert("src_dirents", dirents_array);
+ json_obj.insert("dst_repo_id", dst_repo_id);
+ json_obj.insert("dst_parent_dir", dst_dir_path);
+
+ QJsonDocument json_document(json_obj);
+ return json_document.toJson(QJsonDocument::Compact);
+}
+
+} // namespace
+
+
+GetDirentsRequest::GetDirentsRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path)
+ : SeafileApiRequest (account.getAbsoluteUrl(QString(kGetDirentsUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_GET, account.token),
+ repo_id_(repo_id), path_(path), readonly_(false)
+{
+ setUrlParam("p", path);
+}
+
+void GetDirentsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ QString dir_id = reply.rawHeader("oid");
+ if (dir_id.length() != 40) {
+ emit failed(ApiError::fromHttpError(500), repo_id_);
+ return;
+ }
+ // this extra header column only supported from v4.2 seahub
+ readonly_ = reply.rawHeader("dir_perm") == "r";
+
+ json_t *root = parseJSON(reply, &error);
+ if (!root) {
+ qDebug("GetDirentsRequest: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError(), repo_id_);
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QList<SeafDirent> dirents;
+ dirents = SeafDirent::listFromJSON(json.data(), &error);
+ emit success(readonly_, dirents, repo_id_);
+}
+
+GetFileDownloadLinkRequest::GetFileDownloadLinkRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetFilesUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_GET, account.token)
+{
+ setUrlParam("p", path);
+}
+
+void GetFileDownloadLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+ QString reply_content(reply.readAll());
+ QString oid;
+
+ if (reply.hasRawHeader("oid"))
+ oid = reply.rawHeader("oid");
+
+ do {
+ if (reply_content.size() <= 2)
+ break;
+ reply_content.remove(0, 1);
+ reply_content.chop(1);
+ QUrl new_url(reply_content);
+
+ if (!new_url.isValid())
+ break;
+
+ file_id_ = oid;
+ emit success(reply_content);
+ return;
+ } while (0);
+ emit failed(ApiError::fromHttpError(500));
+}
+
+GetSharedLinkRequest::GetSharedLinkRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ bool is_file)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetFileSharedLinkUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_PUT, account.token), repo_id_(repo_id)
+{
+ setFormParam("type", is_file ? "f" : "d");
+ setFormParam("p", path);
+}
+
+void GetSharedLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+ QString reply_content(reply.rawHeader("Location"));
+
+ emit success(reply_content, repo_id_);
+}
+
+CreateDirectoryRequest::CreateDirectoryRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ bool create_parents)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetDirentsUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ repo_id_(repo_id), path_(path), create_parents_(create_parents)
+{
+ setUrlParam("p", path);
+
+ setFormParam("operation", "mkdir");
+ setFormParam("create_parents", create_parents ? "true" : "false");
+}
+
+void CreateDirectoryRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success(repo_id_);
+}
+
+GetFileUploadLinkRequest::GetFileUploadLinkRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ bool use_upload)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(
+ use_upload ? kGetFileUploadUrl : kGetFileUpdateUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_GET, account.token)
+{
+ setUrlParam("p", path);
+}
+
+void GetFileUploadLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+ QString reply_content(reply.readAll());
+
+ do {
+ if (reply_content.size() <= 2)
+ break;
+ reply_content.remove(0, 1);
+ reply_content.chop(1);
+ QUrl new_url(reply_content);
+
+ if (!new_url.isValid())
+ break;
+
+ emit success(reply_content);
+ return;
+ } while (0);
+ emit failed(ApiError::fromHttpError(500));
+}
+
+
+RenameDirentRequest::RenameDirentRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ const QString &new_name,
+ bool is_file)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(
+ QString(is_file ? kGetFilesUrl: kGetDirentsUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ is_file_(is_file), repo_id_(repo_id), path_(path), new_name_(new_name)
+{
+ setUrlParam("p", path);
+
+ setFormParam("operation", "rename");
+ setFormParam("newname", new_name);
+}
+
+void RenameDirentRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success(repo_id_);
+}
+
+RemoveDirentRequest::RemoveDirentRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ bool is_file)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(
+ QString(is_file ? kGetFilesUrl : kGetDirentsUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_DELETE, account.token),
+ is_file_(is_file), repo_id_(repo_id), path_(path)
+{
+ setUrlParam("p", path);
+}
+
+void RemoveDirentRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success(repo_id_);
+}
+
+RemoveDirentsRequest::RemoveDirentsRequest(const Account &account,
+ const QString &repo_id,
+ const QString &parent_path,
+ const QStringList& filenames)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(
+ QString(kRemoveDirentsURL).arg(repo_id)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ repo_id_(repo_id), parent_path_(parent_path), filenames_(filenames)
+{
+ setUrlParam("p", parent_path_);
+ setFormParam("file_names", filenames_.join(":"));
+}
+
+void RemoveDirentsRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success(repo_id_);
+}
+
+
+MoveFileRequest::MoveFileRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetFilesUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_POST, account.token)
+{
+ setUrlParam("p", path);
+
+ setFormParam("operation", "move");
+ setFormParam("dst_repo", dst_repo_id);
+ setFormParam("dst_dir", dst_dir_path);
+}
+
+void MoveFileRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+
+QueryAsyncOperationProgress::QueryAsyncOperationProgress(const Account &account,
+ const QString& task_id)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(kQueryAsyncOperationProgressUrl),
+ SeafileApiRequest::METHOD_GET, account.token)
+{
+ setUrlParam("task_id", task_id);
+}
+
+void QueryAsyncOperationProgress::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ return;
+ }
+
+ Json json(root);
+ bool is_success = json.getBool("successful");
+ bool is_failed = json.getBool("failed");
+ if (is_success) {
+ emit success();
+ } else if (is_failed) {
+ qWarning("operation failed");
+ emit failed(ApiError::fromHttpError(500));
+ }
+}
+
+
+AsyncCopyAndMoveOneItemRequest::AsyncCopyAndMoveOneItemRequest(const Account &account,
+ const QString &src_repo_id,
+ const QString &src_parent_dir,
+ const QString &src_dirent_name,
+ const QString &dst_repo_id,
+ const QString &dst_parent_dir,
+ const QString &operation,
+ const QString &dirent_type)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kCopyMoveSingleItemUrl)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ account_(account),
+ repo_id_(src_repo_id),
+ src_dir_path_(src_parent_dir),
+ src_dirent_name_(src_dirent_name),
+ dst_repo_id_(dst_repo_id),
+ dst_repo_path_(dst_parent_dir),
+ operation_(operation),
+ dirent_type_(dirent_type)
+{
+ setFormParam("src_repo_id", src_repo_id);
+ setFormParam("src_parent_dir", src_parent_dir);
+ setFormParam("src_dirent_name", src_dirent_name);
+ setFormParam("dst_repo_id", dst_repo_id);
+ setFormParam("dst_parent_dir", dst_parent_dir);
+ setFormParam("operation", operation);
+ setFormParam("dirent_type", dirent_type);
+}
+
+void AsyncCopyAndMoveOneItemRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ return;
+ }
+
+ Json json(root);
+ QString task_id= json.getString("task_id");
+ emit success(task_id);
+}
+
+
+// Asynchronous copy multiple items
+AsyncCopyMultipleItemsRequest::AsyncCopyMultipleItemsRequest(const Account &account,
+ const QString &repo_id,
+ const QString &src_dir_path,
+ const QMap<QString, int>&src_dirents,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kAsyncCopyMultipleItems)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ account_(account),
+ repo_id_(repo_id),
+ src_dir_path_(src_dir_path),
+ src_dirents_(src_dirents),
+ dst_repo_id_(dst_repo_id),
+ dst_repo_path_(dst_dir_path)
+
+{
+
+ setHeader("Content-Type","application/json");
+ setHeader("Accept", "application/json");
+
+ QStringList file_names;
+ for ( const QString & file_name : src_dirents.keys()) {
+ file_names.push_back(file_name);
+ }
+ QByteArray byte_array = assembleJsonReq(repo_id, src_dir_path, file_names,
+ dst_repo_id, dst_dir_path);
+ setRequestBody(byte_array);
+}
+
+void AsyncCopyMultipleItemsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ return;
+ }
+
+ Json json(root);
+ QString task_id = json.getString("task_id");
+ emit success(task_id);
+}
+
+
+// Asynchronous api for move multiple items
+AsyncMoveMultipleItemsRequest::AsyncMoveMultipleItemsRequest(const Account &account,
+ const QString &repo_id,
+ const QString &src_dir_path,
+ const QMap<QString, int> &src_dirents,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kAsyncMoveMultipleItems)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ account_(account),
+ repo_id_(repo_id),
+ src_dir_path_(src_dir_path),
+ src_dirents_(src_dirents),
+ dst_repo_id_(dst_repo_id),
+ dst_repo_path_(dst_dir_path)
+{
+ setHeader("Content-Type","application/json");
+ setHeader("Accept", "application/json");
+
+ QStringList file_names;
+ for ( const QString & file_name : src_dirents.keys()) {
+ file_names.push_back(file_name);
+ }
+
+ QByteArray byte_array = assembleJsonReq(repo_id, src_dir_path, file_names,
+ dst_repo_id, dst_dir_path);
+ setRequestBody(byte_array);
+}
+
+void AsyncMoveMultipleItemsRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ return;
+ }
+
+ Json json(root);
+ QString task_id = json.getString("task_id");
+ emit success(task_id);
+}
+
+
+CopyMultipleFilesRequest::CopyMultipleFilesRequest(const Account &account,
+ const QString &repo_id,
+ const QString &src_dir_path,
+ const QStringList &src_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kFileOperationCopy).arg(repo_id)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ repo_id_(repo_id),
+ src_dir_path_(src_dir_path),
+ src_file_names_(src_file_names),
+ dst_repo_id_(dst_repo_id)
+{
+ setUrlParam("p", src_dir_path);
+
+ setFormParam("file_names", src_file_names.join(":"));
+ setFormParam("dst_repo", dst_repo_id);
+ setFormParam("dst_dir", dst_dir_path);
+}
+
+void CopyMultipleFilesRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success(dst_repo_id_);
+}
+
+MoveMultipleFilesRequest::MoveMultipleFilesRequest(const Account &account,
+ const QString &repo_id,
+ const QString &src_dir_path,
+ const QStringList &src_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kFileOperationMove).arg(repo_id)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ repo_id_(repo_id),
+ src_dir_path_(src_dir_path),
+ src_file_names_(src_file_names),
+ dst_repo_id_(dst_repo_id)
+{
+ setUrlParam("p", src_dir_path);
+
+ setFormParam("file_names", src_file_names.join(":"));
+ setFormParam("dst_repo", dst_repo_id);
+ setFormParam("dst_dir", dst_dir_path);
+}
+
+void MoveMultipleFilesRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success(dst_repo_id_);
+}
+
+StarFileRequest::StarFileRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(kGetStarredFilesUrl),
+ SeafileApiRequest::METHOD_POST, account.token)
+{
+ setFormParam("repo_id", repo_id);
+ setFormParam("p", path);
+}
+
+void StarFileRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+UnstarFileRequest::UnstarFileRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(kGetStarredFilesUrl),
+ SeafileApiRequest::METHOD_DELETE, account.token)
+{
+ setUrlParam("repo_id", repo_id);
+ setUrlParam("p", path);
+}
+
+void UnstarFileRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success();
+}
+
+LockFileRequest::LockFileRequest(const Account &account, const QString &repo_id,
+ const QString &path, bool lock)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetFilesUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_PUT, account.token),
+ lock_(lock), repo_id_(repo_id), path_(path)
+{
+ setFormParam("p", path.startsWith("/") ? path : "/" + path);
+
+ setFormParam("operation", lock ? "lock" : "unlock");
+}
+
+void LockFileRequest::requestSuccess(QNetworkReply& reply)
+{
+ emit success(repo_id_);
+}
+
+GetFileUploadedBytesRequest::GetFileUploadedBytesRequest(
+ const Account &account,
+ const QString &repo_id,
+ const QString &parent_dir,
+ const QString &file_name)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetFileUploadedBytesUrl).arg(repo_id)),
+ SeafileApiRequest::METHOD_GET,
+ account.token),
+ repo_id_(repo_id),
+ parent_dir_(parent_dir),
+ file_name_(file_name)
+{
+ setUrlParam("parent_dir",
+ parent_dir.startsWith("/") ? parent_dir : "/" + parent_dir);
+ setUrlParam("file_name", file_name);
+}
+
+void GetFileUploadedBytesRequest::requestSuccess(QNetworkReply &reply)
+{
+ QString accept_ranges_header = reply.rawHeader("Accept-Ranges");
+ // printf ("accept_ranges_header = %s\n", toCStr(accept_ranges_header));
+ if (accept_ranges_header != "bytes") {
+ // Chunked uploading is not supported on the server
+ emit success(false, 0);
+ return;
+ }
+
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetFileUploadedBytesRequest: failed to parse json:%s\n",
+ error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ quint64 uploaded_bytes = dict["uploadedBytes"].toLongLong();
+ // printf ("uploadedBytes = %lld\n", uploaded_bytes);
+ emit success(true, uploaded_bytes);
+}
+
+GetIndexProgressRequest::GetIndexProgressRequest(const QUrl &url, const QString &task_id)
+ : SeafileApiRequest(url, SeafileApiRequest::METHOD_GET)
+{
+ setUrlParam("task_id", task_id);
+}
+
+void GetIndexProgressRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t *root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("GetIndexProgressRequest: failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ ServerIndexProgress result;
+
+ result.total = dict.value("total").toInt();
+ result.indexed = dict.value("indexed").toInt();
+ result.status = dict.value("status").toInt();
+ emit success(result);
+}
+
+GetSmartLinkRequest::GetSmartLinkRequest(const Account& account,
+ const QString &repo_id,
+ const QString &path,
+ bool is_dir)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetSmartLink)),
+ SeafileApiRequest::METHOD_GET, account.token),
+ repo_id_(repo_id),
+ path_(path),
+ is_dir_(is_dir),
+ protocol_link_(OpenLocalHelper::instance()->generateLocalFileSeafileUrl(repo_id, account, path).toEncoded())
+{
+ setUrlParam("repo_id", repo_id);
+ setUrlParam("path", path);
+ setUrlParam("is_dir", is_dir ? "true" : "false");
+}
+
+void GetSmartLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ const char* smart_link =
+ json_string_value(json_object_get(json.data(), "smart_link"));
+
+ emit success(smart_link, protocol_link_);
+}
+
+GetFileLockInfoRequest::GetFileLockInfoRequest(const Account& account,
+ const QString &repo_id,
+ const QString &path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetDirentsUrl)),
+ SeafileApiRequest::METHOD_GET, account.token),
+ path_(path)
+{
+ // Seahub doesn't provide a standalone api for getting file lock
+ // info. We have to get that from dirents api.
+ dirents_req_.reset(
+ new GetDirentsRequest(account, repo_id, ::getParentPath(path_)));
+ connect(dirents_req_.data(),
+ SIGNAL(success(bool, const QList<SeafDirent> &, const QString &)),
+ this,
+ SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent> &)));
+ connect(dirents_req_.data(),
+ SIGNAL(failed(const ApiError &)),
+ this,
+ SIGNAL(failed(const ApiError &)));
+}
+
+void GetFileLockInfoRequest::send()
+{
+ dirents_req_->send();
+}
+
+void GetFileLockInfoRequest::requestSuccess(QNetworkReply& reply)
+{
+ // Just a place holder. A `GetFileLockInfoRequest` is a wrapper around a
+ // `GetDirentsRequest`, which really sends the api
+ // requests.
+}
+
+void GetFileLockInfoRequest::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents)
+{
+ const QString name = ::getBaseName(path_);
+ foreach(const SeafDirent& dirent, dirents) {
+ if (dirent.name == name) {
+ const QString lock_owner = dirent.getLockOwnerDisplayString();
+ if (!lock_owner.isEmpty()) {
+ emit success(true, lock_owner);
+ } else {
+ emit success(false, "");
+ }
+ return;
+ }
+ }
+ emit success(false, "");
+}
+
+GetUploadLinkRequest::GetUploadLinkRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path)
+ : SeafileApiRequest(
+ account.getAbsoluteUrl(QString(kGetUploadLinkUrl)),
+ SeafileApiRequest::METHOD_POST, account.token),
+ path_(path)
+{
+ setFormParam("repo_id", repo_id);
+ setFormParam("path", path);
+}
+
+void GetUploadLinkRequest::requestSuccess(QNetworkReply& reply)
+{
+ json_error_t error;
+ json_t* root = parseJSON(reply, &error);
+ if (!root) {
+ qWarning("failed to parse json:%s\n", error.text);
+ emit failed(ApiError::fromJsonError());
+ return;
+ }
+ QScopedPointer<json_t, JsonPointerCustomDeleter> json(root);
+ QMap<QString, QVariant> dict = mapFromJSON(json.data(), &error);
+ QString upload_link = dict["link"].toString();
+ emit success(upload_link);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_REQUESTS_H
+#define SEAFILE_CLIENT_FILE_BROWSER_REQUESTS_H
+
+#include <QList>
+#include <QStringList>
+#include <QTimer>
+
+#include "api/api-request.h"
+#include "seaf-dirent.h"
+
+class SeafDirent;
+class Account;
+class QDir;
+
+class GetDirentsRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ GetDirentsRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path);
+
+ const QString& repoId() const { return repo_id_; }
+ const QString& path() const { return path_; }
+
+signals:
+ void success(bool current_readonly, const QList<SeafDirent> &dirents, const QString& repo_id);
+ void failed(const ApiError& error, const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetDirentsRequest)
+
+ const QString repo_id_;
+ const QString path_;
+ bool readonly_;
+};
+
+class GetFileDownloadLinkRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ GetFileDownloadLinkRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path);
+
+ QString fileId() const { return file_id_; }
+signals:
+ void success(const QString& url);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetFileDownloadLinkRequest)
+
+ QString file_id_;
+};
+
+// TODO:
+// intergrate file creation into this class
+class CreateDirectoryRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ CreateDirectoryRequest(const Account &account, const QString &repo_id,
+ const QString &path, bool create_parents = false);
+ const QString &repoId() { return repo_id_; }
+ const QString &path() { return path_; }
+
+signals:
+ void success(const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(CreateDirectoryRequest)
+ const QString repo_id_;
+ const QString path_;
+ bool create_parents_;
+};
+
+class RenameDirentRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ RenameDirentRequest(const Account &account, const QString &repo_id,
+ const QString &path, const QString &new_path,
+ bool is_file = true);
+
+ const bool& isFile() const { return is_file_; }
+ const QString& repoId() const { return repo_id_; }
+ const QString& path() const { return path_; }
+ const QString& newName() const { return new_name_; }
+
+signals:
+ void success(const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(RenameDirentRequest)
+
+ const bool is_file_;
+ const QString repo_id_;
+ const QString path_;
+ const QString new_name_;
+};
+
+class RemoveDirentRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ RemoveDirentRequest(const Account &account, const QString &repo_id,
+ const QString &path, bool is_file = true);
+
+ const bool& isFile() const { return is_file_; }
+ const QString& repoId() const { return repo_id_; }
+ const QString& path() const { return path_; }
+
+signals:
+ void success(const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(RemoveDirentRequest)
+
+ const bool is_file_;
+ const QString repo_id_;
+ const QString path_;
+};
+
+class RemoveDirentsRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ RemoveDirentsRequest(const Account &account,
+ const QString &repo_id,
+ const QString &parent_path,
+ const QStringList& filenames);
+
+ const QString& repoId() const { return repo_id_; }
+ const QString& parentPath() const { return parent_path_; }
+ const QStringList& filenames() const { return filenames_; }
+
+signals:
+ void success(const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(RemoveDirentsRequest)
+
+ const QString repo_id_;
+ const QString parent_path_;
+ const QStringList filenames_;
+};
+
+
+class GetSharedLinkRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ GetSharedLinkRequest(const Account &account, const QString &repo_id,
+ const QString &path, bool is_file);
+
+signals:
+ void success(const QString& url, const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetSharedLinkRequest)
+ const QString repo_id_;
+};
+
+class GetFileUploadLinkRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ GetFileUploadLinkRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ bool use_upload = true);
+
+signals:
+ void success(const QString& url);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetFileUploadLinkRequest)
+};
+
+// Single File only
+class MoveFileRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ MoveFileRequest(const Account &account,
+ const QString &repo_id,
+ const QString &path,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path);
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(MoveFileRequest)
+};
+
+class CopyMultipleFilesRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ CopyMultipleFilesRequest(const Account &account,
+ const QString &repo_id,
+ const QString &src_dir_path,
+ const QStringList &src_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path);
+ const QString& repoId() { return repo_id_; }
+ const QString& srcPath() { return src_dir_path_; }
+ const QStringList& srcFileNames() { return src_file_names_; }
+
+signals:
+ void success(const QString& dst_repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(CopyMultipleFilesRequest)
+ const QString repo_id_;
+ const QString src_dir_path_;
+ const QStringList src_file_names_;
+ const QString dst_repo_id_;
+};
+
+class MoveMultipleFilesRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ MoveMultipleFilesRequest(const Account &account,
+ const QString &repo_id,
+ const QString &src_dir_path,
+ const QStringList &src_file_names,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path);
+ const QString& srcRepoId() { return repo_id_; }
+ const QString& srcPath() { return src_dir_path_; }
+ const QStringList& srcFileNames() { return src_file_names_; }
+
+signals:
+ void success(const QString& dst_repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(MoveMultipleFilesRequest)
+ const QString repo_id_;
+ const QString src_dir_path_;
+ const QStringList src_file_names_;
+ const QString dst_repo_id_;
+};
+
+
+// Query asynchronous operation progress
+class QueryAsyncOperationProgress : public SeafileApiRequest {
+Q_OBJECT
+public:
+ QueryAsyncOperationProgress(const Account &account,
+ const QString &task_id);
+signals:
+ void success();
+
+private slots:
+ void requestSuccess(QNetworkReply& reply);
+
+};
+
+// Async copy and move a single item
+class AsyncCopyAndMoveOneItemRequest : public SeafileApiRequest {
+Q_OBJECT
+public:
+ AsyncCopyAndMoveOneItemRequest(const Account &account,
+ const QString &src_repo_id,
+ const QString &src_parent_dir,
+ const QString &src_dirent_name,
+ const QString &dst_repo_id,
+ const QString &dst_parent_dir,
+ const QString &operation,
+ const QString &dirent_type);
+
+signals:
+ void success(const QString& task_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ const Account& account_;
+ const QString repo_id_;
+ const QString src_dir_path_;
+ const QString src_dirent_name_;
+ const QString dst_repo_id_;
+ const QString dst_repo_path_;
+ const QString operation_;
+ const QString dirent_type_;
+ Q_DISABLE_COPY(AsyncCopyAndMoveOneItemRequest)
+};
+
+
+// Batch copy items asynchronously
+class AsyncCopyMultipleItemsRequest : public SeafileApiRequest {
+Q_OBJECT
+public:
+
+ AsyncCopyMultipleItemsRequest (const Account &account, const QString &repo_id,
+ const QString &src_dir_path,
+ const QMap<QString, int>&src_dirents,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path);
+signals:
+ void success(const QString& task_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ const Account& account_;
+ const QString repo_id_;
+ const QString src_dir_path_;
+ QMap<QString, int> src_dirents_;
+ const QString dst_repo_id_;
+ const QString dst_repo_path_;
+ Q_DISABLE_COPY(AsyncCopyMultipleItemsRequest)
+};
+
+// Batch move items asynchronously
+class AsyncMoveMultipleItemsRequest : public SeafileApiRequest {
+Q_OBJECT
+public:
+ AsyncMoveMultipleItemsRequest(const Account &account,
+ const QString &repo_id,
+ const QString &src_dir_path,
+ const QMap<QString, int> &src_dirents,
+ const QString &dst_repo_id,
+ const QString &dst_dir_path);
+signals:
+ void success(const QString& task_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ const Account& account_;
+ const QString repo_id_;
+ const QString src_dir_path_;
+ QMap<QString, int> src_dirents_;
+ const QString dst_repo_id_;
+ const QString dst_repo_path_;
+ Q_DISABLE_COPY(AsyncMoveMultipleItemsRequest)
+};
+
+class StarFileRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ StarFileRequest(const Account &account, const QString &repo_id,
+ const QString &path);
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(StarFileRequest)
+};
+
+class UnstarFileRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ UnstarFileRequest(const Account &account, const QString &repo_id,
+ const QString &path);
+
+signals:
+ void success();
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(UnstarFileRequest)
+};
+
+class LockFileRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ LockFileRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ bool lock);
+
+ bool lock() const { return lock_; }
+ const QString & repoId() const { return repo_id_; }
+ const QString & path() const { return path_; }
+
+signals:
+ void success(const QString& repo_id);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(LockFileRequest);
+ const bool lock_;
+ const QString repo_id_;
+ const QString path_;
+};
+
+class GetFileUploadedBytesRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ GetFileUploadedBytesRequest(const Account& account,
+ const QString& repo_id,
+ const QString& parent_dir,
+ const QString& file_name);
+
+ const QString & repoId() const { return repo_id_; }
+ const QString & parentDir() const { return parent_dir_; }
+ const QString & fileName() const { return file_name_; }
+
+signals:
+ void success(bool support_chunked_uploading, quint64 uploaded_bytes);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetFileUploadedBytesRequest);
+ const QString repo_id_;
+ const QString parent_dir_;
+ const QString file_name_;
+};
+
+struct ServerIndexProgress {
+ qint64 total;
+ qint64 indexed;
+ qint64 status;
+};
+
+class GetIndexProgressRequest : public SeafileApiRequest {
+ Q_OBJECT
+public:
+ GetIndexProgressRequest(const QUrl &url, const QString &task_id);
+signals:
+ void success(const ServerIndexProgress& result);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetIndexProgressRequest);
+};
+
+class GetSmartLinkRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetSmartLinkRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ bool is_dir);
+
+signals:
+ void success(const QString &smart_link, const QString &protocol_link);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetSmartLinkRequest);
+ QString repo_id_;
+ QString path_;
+ QString protocol_link_;
+ bool is_dir_;
+};
+
+class GetFileLockInfoRequest : public SeafileApiRequest
+{
+ Q_OBJECT
+public:
+ GetFileLockInfoRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path);
+
+ virtual void send() Q_DECL_OVERRIDE;
+
+ const QString& path() const { return path_; }
+
+signals:
+ void success(bool found, const QString& lock_owner);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+ void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents);
+
+private:
+ Q_DISABLE_COPY(GetFileLockInfoRequest);
+
+ const QString path_;
+ QScopedPointer<GetDirentsRequest, QScopedPointerDeleteLater> dirents_req_;
+};
+
+class GetUploadLinkRequest : public SeafileApiRequest
+{
+Q_OBJECT
+public:
+ GetUploadLinkRequest(const Account& account,
+ const QString& repo_id,
+ const QString& path);
+ const QString& path() const { return path_; }
+signals:
+ void success(const QString& upload_link);
+
+protected slots:
+ void requestSuccess(QNetworkReply& reply);
+
+private:
+ Q_DISABLE_COPY(GetUploadLinkRequest);
+ QString path_;
+};
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_REQUESTS_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "file-browser-dialog.h"
+#include "file-browser-search-tab.h"
+#include "ui/main-window.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "seafile-applet.h"
+#include "api/requests.h"
+#include "repo-service.h"
+
+namespace {
+
+enum {
+ FILE_COLUMN_NAME = 0,
+ FILE_COLUMN_MTIME,
+ FILE_COLUMN_SIZE,
+ FILE_MAX_COLUMN
+};
+
+int kMarginLeft = 9;
+const int kDefaultColumnWidth = 120;
+const int kDefaultColumnHeight = 40;
+const int kColumnIconSize = 28;
+const int kFileNameColumnWidth = 200;
+const int kExtraPadding = 30;
+const int kDefaultColumnSum = kFileNameColumnWidth + kDefaultColumnWidth * 3 + kExtraPadding;
+const int kFileStatusIconSize = 16;
+const int kMarginBetweenFileNameAndStatusIcon = 5;
+
+const QColor kSelectedItemBackgroundcColor("#F9E0C7");
+const QColor kItemBackgroundColor("white");
+const QColor kItemBottomBorderColor("#ECECEC");
+const QColor kFileNameFontColor("black");
+const QColor kFontColor("#757575");
+
+} // anonymous namespace
+
+FileBrowserSearchItemDelegate::FileBrowserSearchItemDelegate(QObject *parent)
+ : QStyledItemDelegate(parent) {
+
+}
+
+void FileBrowserSearchItemDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ const FileBrowserSearchModel *model = static_cast<const FileBrowserSearchModel*>(index.model());
+
+ // fix for the last item
+ QRect option_rect = option.rect;
+
+ // draw item's background
+ painter->save();
+ if (option.state & QStyle::State_Selected)
+ painter->fillRect(option_rect, kSelectedItemBackgroundcColor);
+ else
+ painter->fillRect(option_rect, kItemBackgroundColor);
+ painter->restore();
+
+ //
+ // draw item's border
+ //
+
+ // draw item's border for the first row only
+ static const QPen borderPen(kItemBottomBorderColor, 1);
+ if (index.row() == 0) {
+ painter->save();
+ painter->setPen(borderPen);
+ painter->drawLine(option_rect.topLeft(), option_rect.topRight());
+ painter->restore();
+ }
+ // draw item's border under the bottom
+ painter->save();
+ painter->setPen(borderPen);
+ painter->drawLine(option_rect.bottomLeft(), option_rect.bottomRight());
+ painter->restore();
+
+ QSize size = model->data(index, Qt::SizeHintRole).value<QSize>();
+ QString text = model->data(index, Qt::DisplayRole).value<QString>();
+ switch (index.column()) {
+ case FILE_COLUMN_NAME:
+ {
+ // draw icon
+ QPixmap pixmap = model->data(index, Qt::DecorationRole).value<QPixmap>();
+ double scale_factor = globalDevicePixelRatio();
+ // On Mac OSX (and other HDPI screens) the pixmap would be the 2x
+ // version (but the draw rect area is still the same size), so when
+ // computing the offsets we need to divide it by the scale factor.
+ int icon_width = qMin(kColumnIconSize,
+ int((double)pixmap.width() / (double)scale_factor));
+ int icon_height = qMin(size.height(),
+ int((double)pixmap.height() / (double)scale_factor));
+ int alignX = (kColumnIconSize - icon_width) / 2;
+ int alignY = (size.height() - icon_height) / 2;
+
+#ifdef Q_OS_WIN32
+ kMarginLeft = 4;
+#endif
+
+ QRect icon_bound_rect(
+ option_rect.topLeft() + QPoint(kMarginLeft + alignX, alignY - 2),
+ QSize(icon_width, icon_height));
+
+ painter->save();
+ painter->drawPixmap(icon_bound_rect, pixmap);
+ painter->restore();
+
+ // draw text
+ QFont font = model->data(index, Qt::FontRole).value<QFont>();
+ QRect rect(option_rect.topLeft() + QPoint(kMarginLeft + 2 * 2 + kColumnIconSize, -2),
+ size - QSize(kColumnIconSize + kMarginLeft, 0));
+ painter->setPen(kFileNameFontColor);
+ painter->setFont(font);
+ painter->drawText(
+ rect,
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
+ fitTextToWidth(
+ text,
+ option.font,
+ rect.width() - kMarginBetweenFileNameAndStatusIcon - kFileStatusIconSize - 5));
+
+ }
+ break;
+
+ case FILE_COLUMN_SIZE:
+ if (!text.isEmpty())
+ text = ::readableFileSize(model->data(index, Qt::DisplayRole).value<quint64>());
+ case FILE_COLUMN_MTIME:
+ {
+ if (index.column() == FILE_COLUMN_MTIME) {
+ text = ::translateCommitTime(model->data(index, Qt::DisplayRole).value<quint64>(), true);
+ }
+ QFont font = model->data(index, Qt::FontRole).value<QFont>();
+ QRect rect(option_rect.topLeft() + QPoint(9, -2), size - QSize(10, 0));
+ painter->save();
+ painter->setPen(kFontColor);
+ painter->setFont(font);
+ painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, text);
+ painter->restore();
+ }
+ break;
+ default:
+ qWarning() << "invalid item (row)";
+ break;
+ }
+}
+
+FileBrowserSearchView::FileBrowserSearchView(QWidget* parent)
+ : QTableView(parent),
+ parent_(qobject_cast<FileBrowserDialog*>(parent)),
+ search_model_(NULL),
+ proxy_model_(NULL)
+{
+ verticalHeader()->hide();
+ verticalHeader()->setDefaultSectionSize(kDefaultColumnHeight);
+ horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+ horizontalHeader()->setStretchLastSection(true);
+ horizontalHeader()->setCascadingSectionResizes(true);
+ horizontalHeader()->setHighlightSections(false);
+ horizontalHeader()->setSortIndicatorShown(true);
+ horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+
+ setGridStyle(Qt::NoPen);
+ setShowGrid(false);
+ setContentsMargins(0, 0, 0, 0);
+ setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ setMouseTracking(true);
+ setDragDropMode(QAbstractItemView::DropOnly);
+
+ connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+ setupContextMenu();
+}
+
+void FileBrowserSearchView::setupContextMenu()
+{
+ context_menu_ = new QMenu(this);
+ connect(parent_, SIGNAL(aboutToClose()),
+ context_menu_, SLOT(close()));
+ open_parent_dir_action_ = new QAction(tr("&Show in folder"), this);
+ open_parent_dir_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+ open_parent_dir_action_->setIconVisibleInMenu(true);
+ open_parent_dir_action_->setStatusTip(tr("Show in folder"));
+ connect(open_parent_dir_action_, SIGNAL(triggered()),
+ this, SLOT(openParentDir()));
+ context_menu_->addAction(open_parent_dir_action_);
+ this->addAction(open_parent_dir_action_);
+}
+
+void FileBrowserSearchView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPoint position = event->pos();
+ const QModelIndex proxy_index = indexAt(position);
+ position = viewport()->mapToGlobal(position);
+ if (!proxy_index.isValid()) {
+ return;
+ }
+
+ const QModelIndex index = proxy_model_->mapToSource(proxy_index);
+ const int row = index.row();
+ const FileSearchResult *result = search_model_->resultAt(row);
+ if (!result)
+ return;
+
+ QItemSelectionModel *selections = this->selectionModel();
+ QModelIndexList selected = selections->selectedRows();
+ if (selected.size() == 1) {
+ open_parent_dir_action_->setEnabled(true);
+ search_item_.reset(new FileSearchResult(*result));
+ } else {
+ open_parent_dir_action_->setEnabled(false);
+ return;
+ }
+
+ context_menu_->exec(position); // synchronously
+ search_item_.reset(NULL);
+}
+
+void FileBrowserSearchView::openParentDir()
+{
+ parent_->enterPath(::getParentPath(search_item_->fullpath));
+ emit clearSearchBar();
+}
+
+void FileBrowserSearchView::onItemDoubleClicked(const QModelIndex& index)
+{
+ const FileSearchResult *result =
+ search_model_->resultAt(proxy_model_->mapToSource(index).row());
+ if (result->name.isEmpty() || result->fullpath.isEmpty())
+ return;
+
+ if (result->fullpath.endsWith("/"))
+ emit clearSearchBar();
+
+ RepoService::instance()->openLocalFile(result->repo_id, result->fullpath);
+}
+
+void FileBrowserSearchView::setModel(QAbstractItemModel *model)
+{
+ search_model_ = qobject_cast<FileBrowserSearchModel*>(model);
+ if (!search_model_)
+ return;
+ proxy_model_ = new FileSearchSortFilterProxyModel(search_model_);
+ proxy_model_->setSourceModel(search_model_);
+ QTableView::setModel(proxy_model_);
+
+// setColumnHidden(FILE_COLUMN_PROGRESS, true);
+ connect(model, SIGNAL(modelAboutToBeReset()), this, SLOT(onAboutToReset()));
+ setSortingEnabled(true);
+
+ // set default sort by folder
+ sortByColumn(FILE_COLUMN_NAME, Qt::AscendingOrder);
+}
+
+void FileBrowserSearchView::onAboutToReset()
+{
+ search_item_.reset(NULL);
+}
+
+void FileBrowserSearchView::resizeEvent(QResizeEvent *event)
+{
+ QTableView::resizeEvent(event);
+ if (search_model_)
+ search_model_->onResize(event->size());
+}
+
+FileBrowserSearchModel::FileBrowserSearchModel(QObject *parent)
+ : QAbstractTableModel(parent),
+ name_column_width_(kFileNameColumnWidth)
+{
+
+}
+
+void FileBrowserSearchModel::setSearchResult(const std::vector<FileSearchResult>& results)
+{
+ beginResetModel();
+ results_ = results;
+ endResetModel();
+}
+
+int FileBrowserSearchModel::rowCount(const QModelIndex &parent) const
+{
+ return results_.size();
+}
+
+int FileBrowserSearchModel::columnCount(const QModelIndex &index) const
+{
+ return FILE_MAX_COLUMN;
+}
+
+QVariant FileBrowserSearchModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= (int)results_.size()) {
+ return QVariant();
+ }
+ const int column = index.column();
+ const int row = index.row();
+ const FileSearchResult& result = results_[row];
+
+ if (role == Qt::DecorationRole && column == FILE_COLUMN_NAME) {
+ QIcon icon;
+
+ if (result.fullpath.endsWith("/")) {
+ icon = QIcon(":/images/files_v2/file_folder.png");
+ } else {
+ icon = QIcon(getIconByFileNameV2(result.name));
+ }
+
+ return icon.pixmap(kColumnIconSize, kColumnIconSize);
+ }
+
+ if (role == Qt::SizeHintRole) {
+ QSize qsize(kDefaultColumnWidth, kDefaultColumnHeight);
+ switch (column) {
+ case FILE_COLUMN_NAME:
+ qsize.setWidth(name_column_width_);
+ break;
+ case FILE_COLUMN_SIZE:
+ case FILE_COLUMN_MTIME:
+ qsize.setWidth(name_column_width_);
+ default:
+ break;
+ }
+ return qsize;
+ }
+
+ //DisplayRole
+ switch (column) {
+ case FILE_COLUMN_NAME:
+
+ return result.name;
+ case FILE_COLUMN_SIZE:
+ if (result.fullpath.endsWith("/"))
+ return "";
+ return result.size;
+ case FILE_COLUMN_MTIME:
+ return result.last_modified;
+ default:
+ return QVariant();
+ }
+}
+
+QVariant FileBrowserSearchModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Vertical) {
+ return QVariant();
+ }
+
+ if (role == Qt::TextAlignmentRole) {
+ return Qt::AlignLeft + Qt::AlignVCenter;
+ }
+
+ if (role == Qt::DisplayRole) {
+ switch (section) {
+ case FILE_COLUMN_NAME:
+ return tr("Name");
+ case FILE_COLUMN_SIZE:
+ return tr("Size");
+ case FILE_COLUMN_MTIME:
+ return tr("Last Modified");
+ default:
+ return QVariant();
+ }
+ }
+
+ if (role == Qt::FontRole) {
+ QFont font;
+ font.setPixelSize(12);
+ return font;
+ }
+
+ if (role == Qt::ForegroundRole) {
+ return QBrush(kFontColor);
+ }
+
+ if (role == Qt::SizeHintRole && section == FILE_COLUMN_NAME) {
+ if (results_.empty()) {
+ return QSize(name_column_width_, 0);
+ }
+ }
+ return QVariant();
+}
+
+void FileBrowserSearchModel::onResize(const QSize &size)
+{
+ name_column_width_ = size.width() - kDefaultColumnSum + kFileNameColumnWidth;
+ // name_column_width_ should be always larger than kFileNameColumnWidth
+ if (results_.empty())
+ return;
+ emit dataChanged(index(0, FILE_COLUMN_NAME),
+ index(results_.size()-1 , FILE_COLUMN_NAME));
+}
+
+const FileSearchResult* FileBrowserSearchModel::resultAt(int row) const
+{
+ int nSize = static_cast<int>(results_.size());
+ if (row >= nSize)
+ return NULL;
+
+ return &results_[row];
+}
+
+bool FileSearchSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
+{
+ bool is_dir_left = search_model_->resultAt(left.row())->fullpath.endsWith("/");
+ bool is_dir_right = search_model_->resultAt(right.row())->fullpath.endsWith("/");
+ if (is_dir_left != is_dir_right) {
+ return sortOrder() != Qt::AscendingOrder ? is_dir_right
+ : !is_dir_right;
+ }
+ else if ((left.column() == FILE_COLUMN_NAME) &&
+ (right.column() == FILE_COLUMN_NAME)) {
+ const QString left_name = search_model_->resultAt(left.row())->name;
+ const QString right_name = search_model_->resultAt(right.row())->name;
+ return digitalCompare(left_name, right_name) < 0;
+ }
+ else {
+ return QSortFilterProxyModel::lessThan(left, right);
+ }
+}
--- /dev/null
+#ifndef FILE_BROWSER_UI_SEARCH_TAB_H
+#define FILE_BROWSER_UI_SEARCH_TAB_H
+
+#include <vector>
+#include <QTableView>
+#include <QStandardItem>
+#include <QAbstractTableModel>
+#include <QStyledItemDelegate>
+#include <QSortFilterProxyModel>
+
+#include "api/requests.h"
+
+class QAction;
+class QMenu;
+
+class FileBrowserSearchItemDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+public:
+ FileBrowserSearchItemDelegate(QObject *parent);
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+class FileBrowserDialog;
+class FileBrowserSearchModel;
+
+class FileBrowserSearchView : public QTableView {
+ Q_OBJECT
+public:
+ FileBrowserSearchView(QWidget *parent);
+ void setModel(QAbstractItemModel *model);
+
+ void resizeEvent(QResizeEvent *event);
+ void setupContextMenu();
+signals:
+ void clearSearchBar();
+private slots:
+ void onAboutToReset();
+ void openParentDir();
+ void onItemDoubleClicked(const QModelIndex& index);
+private:
+
+ Q_DISABLE_COPY(FileBrowserSearchView)
+
+ void contextMenuEvent(QContextMenuEvent *event);
+
+ FileBrowserDialog *parent_;
+ FileBrowserSearchModel *search_model_;
+ QSortFilterProxyModel *proxy_model_;
+
+ QScopedPointer<const FileSearchResult> search_item_;
+ QMenu *context_menu_;
+ QAction *open_parent_dir_action_;
+};
+
+
+class FileBrowserSearchModel : public QAbstractTableModel {
+ Q_OBJECT
+public:
+ FileBrowserSearchModel(QObject *parent=0);
+
+ int rowCount(const QModelIndex &parent=QModelIndex()) const;
+ int columnCount(const QModelIndex &index) const;
+
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ void setSearchResult(const std::vector<FileSearchResult>& results);
+
+ void onResize(const QSize &size);
+
+ const FileSearchResult* resultAt(int row) const;
+
+private:
+ Q_DISABLE_COPY(FileBrowserSearchModel)
+
+ std::vector<FileSearchResult> results_;
+
+ int name_column_width_;
+};
+
+class FileSearchSortFilterProxyModel : public QSortFilterProxyModel {
+ Q_OBJECT
+public:
+ FileSearchSortFilterProxyModel(FileBrowserSearchModel *parent)
+ : QSortFilterProxyModel(parent), search_model_(parent) {
+ setSortCaseSensitivity(Qt::CaseInsensitive);
+ }
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+
+private:
+ FileBrowserSearchModel* search_model_;
+};
+
+
+#endif // FILE_BROWSER_UI_SEARCH_TAB_H
--- /dev/null
+#include <QtGlobal>
+#include <QtWidgets>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "seaf-dirent.h"
+#include "utils/utils-mac.h"
+#include "seafile-applet.h"
+
+#include "file-browser-dialog.h"
+#include "data-mgr.h"
+#include "transfer-mgr.h"
+#include "tasks.h"
+
+#include "file-table.h"
+
+namespace {
+
+enum {
+ FILE_COLUMN_NAME = 0,
+ FILE_COLUMN_MTIME,
+ FILE_COLUMN_SIZE,
+ FILE_COLUMN_MODIFIER,
+ FILE_COLUMN_PROGRESS,
+ FILE_MAX_COLUMN
+};
+
+int kMarginLeft = 9;
+const int kDefaultColumnWidth = 120;
+const int kDefaultColumnHeight = 40;
+const int kColumnIconSize = 28;
+const int kFileNameColumnWidth = 200;
+const int kExtraPadding = 30;
+const int kDefaultColumnSum = kFileNameColumnWidth + kDefaultColumnWidth * 3 + kExtraPadding;
+const int kLockIconSize = 16;
+const int kFileStatusIconSize = 16;
+const int kMarginBetweenFileNameAndStatusIcon = 5;
+
+const int kRefreshProgressInterval = 1000;
+
+const QColor kSelectedItemBackgroundcColor("#F9E0C7");
+const QColor kItemBackgroundColor("white");
+const QColor kItemBottomBorderColor("#ECECEC");
+const QColor kFileNameFontColor("black");
+const QColor kFontColor("#757575");
+const QString kProgressBarStyle("QProgressBar "
+ "{ border: 1px solid grey; border-radius: 2px; } "
+ "QProgressBar::chunk { background-color: #f0f0f0; width: 1px; }");
+
+enum {
+ NOT_LOCKED = 0,
+ LOCKED_BY_ME,
+ LOCKED_BY_OTHERS
+};
+
+const int DirentLockStatusRole = Qt::UserRole + 1;
+const int DirentLockOwnerRole = Qt::UserRole + 2;
+const int DirentCacheStatusRole = Qt::UserRole + 3;
+
+QIcon getFileStatusIcon(AutoUpdateManager::FileStatus file_status)
+{
+ QString icon;
+ const QString prefix = ":/images/sync/";
+ switch (file_status) {
+ case AutoUpdateManager::SYNCED:
+ icon = "status-done";
+ break;
+ case AutoUpdateManager::UPLOADING:
+ icon = "status-syncing";
+ break;
+ case AutoUpdateManager::NOT_SYNCED:
+ icon = "exclamation";
+ break;
+ }
+
+ return QIcon(prefix + icon + ".png");
+}
+
+} // namespace
+
+FileTableViewDelegate::FileTableViewDelegate(QObject *parent)
+ : QStyledItemDelegate(parent) {
+}
+
+void FileTableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ const FileTableModel *model = static_cast<const FileTableModel*>(index.model());
+
+ // fix for the last item
+ QRect option_rect = option.rect;
+
+ // draw item's background
+ painter->save();
+ if (option.state & QStyle::State_Selected)
+ painter->fillRect(option_rect, kSelectedItemBackgroundcColor);
+ else
+ painter->fillRect(option_rect, kItemBackgroundColor);
+ painter->restore();
+
+ //
+ // draw item's border
+ //
+
+ // draw item's border for the first row only
+ static const QPen borderPen(kItemBottomBorderColor, 1);
+ if (index.row() == 0) {
+ painter->save();
+ painter->setPen(borderPen);
+ painter->drawLine(option_rect.topLeft(), option_rect.topRight());
+ painter->restore();
+ }
+ // draw item's border under the bottom
+ painter->save();
+ painter->setPen(borderPen);
+ painter->drawLine(option_rect.bottomLeft(), option_rect.bottomRight());
+ painter->restore();
+
+ //
+ // draw item
+ //
+
+ QSize size = model->data(index, Qt::SizeHintRole).value<QSize>();
+ QString text = model->data(index, Qt::DisplayRole).value<QString>();
+ switch (index.column()) {
+ case FILE_COLUMN_NAME:
+ {
+ // draw icon
+ QPixmap pixmap = model->data(index, Qt::DecorationRole).value<QPixmap>();
+ double scale_factor = globalDevicePixelRatio();
+ // On Mac OSX (and other HDPI screens) the pixmap would be the 2x
+ // version (but the draw rect area is still the same size), so when
+ // computing the offsets we need to divide it by the scale factor.
+ int icon_width = qMin(kColumnIconSize,
+ int((double)pixmap.width() / (double)scale_factor));
+ int icon_height = qMin(size.height(),
+ int((double)pixmap.height() / (double)scale_factor));
+ int alignX = (kColumnIconSize - icon_width) / 2;
+ int alignY = (size.height() - icon_height) / 2;
+
+#ifdef Q_OS_WIN32
+ kMarginLeft = 4;
+#endif
+
+ QRect icon_bound_rect(
+ option_rect.topLeft() + QPoint(kMarginLeft + alignX, alignY - 2),
+ QSize(icon_width, icon_height));
+
+ painter->save();
+ painter->drawPixmap(icon_bound_rect, pixmap);
+ painter->restore();
+
+ int lock_status = model->data(index, DirentLockStatusRole).toInt();
+ if (lock_status != NOT_LOCKED) {
+ painter->save();
+ QString image = QString(":/images/filebrowser/%1.png").arg(
+ lock_status == LOCKED_BY_ME ? "locked-by-me" : "locked");
+ QPixmap locked_pixmap = QIcon(image).pixmap(kLockIconSize, kLockIconSize);
+ int alignX = (kColumnIconSize / 2) + 3;
+ int alignY = (kColumnIconSize / 2) + 2;
+ painter->drawPixmap(option_rect.topLeft() + QPoint(kMarginLeft + alignX, alignY), locked_pixmap);
+ painter->restore();
+ }
+
+ // draw text
+ QFont font = model->data(index, Qt::FontRole).value<QFont>();
+ QRect rect(option_rect.topLeft() + QPoint(kMarginLeft + 2 * 2 + kColumnIconSize, -2),
+ size - QSize(kColumnIconSize + kMarginLeft, 0));
+ painter->setPen(kFileNameFontColor);
+ painter->setFont(font);
+ painter->drawText(
+ rect,
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine,
+ fitTextToWidth(
+ text,
+ option.font,
+ rect.width() - kMarginBetweenFileNameAndStatusIcon - kFileStatusIconSize - 5));
+
+ QVariant file_status_v = model->data(index, DirentCacheStatusRole);
+ if (!file_status_v.isNull()) {
+ AutoUpdateManager::FileStatus file_status = (AutoUpdateManager::FileStatus)file_status_v.toInt();
+ // printf ("file status is %d\n", (int)file_status);
+
+ QPoint status_icon_pos = option.rect.topRight() - QPoint(kFileStatusIconSize + 3, 0);
+ status_icon_pos.setY(option.rect.center().y() - (kFileStatusIconSize / 2));
+ QRect status_icon_rect(status_icon_pos, QSize(kFileStatusIconSize, kFileStatusIconSize));
+
+ QPixmap status_icon_pixmap = getFileStatusIcon(file_status).pixmap(status_icon_rect.size());
+ qDebug("file browser icon status is %d\n", (int)file_status);
+
+ painter->save();
+ painter->drawPixmap(status_icon_rect, status_icon_pixmap);
+ painter->restore();
+ }
+ }
+ break;
+ case FILE_COLUMN_SIZE:
+ {
+ // if we has progress, draw the progress bar
+ QString text_progress = model->data(model->index(index.row(), FILE_COLUMN_PROGRESS), Qt::DisplayRole).value<QString>();
+ if (!text_progress.isEmpty()) {
+ // get the progress value from the Model
+ if (text_progress.endsWith('%'))
+ text_progress.resize(text_progress.size() - 1);
+ const int progress = text_progress.toInt();
+
+ // Customize style using style-sheet..
+ QProgressBar progressBar;
+ progressBar.resize(QSize(size.width() - 155, size.height() / 2 - 4));
+ progressBar.setMinimum(0);
+ progressBar.setMaximum(100);
+ progressBar.setValue(progress);
+ progressBar.setAlignment(Qt::AlignCenter);
+ progressBar.setStyleSheet(kProgressBarStyle);
+ painter->save();
+ painter->translate(option_rect.topLeft() + QPoint(0, size.height() / 4 - 1));
+ progressBar.render(painter);
+ painter->restore();
+ break;
+ }
+ // else, draw the text only
+ }
+ // FILE_COLUMN_SIZE comes here
+ if (!text.isEmpty())
+ text = ::readableFileSize(model->data(index, Qt::DisplayRole).value<quint64>());
+ // no break, continue
+ case FILE_COLUMN_MTIME:
+ if (index.column() == FILE_COLUMN_MTIME)
+ text = ::translateCommitTime(model->data(index, Qt::DisplayRole).value<quint64>(), true);
+ // no break, continue
+ case FILE_COLUMN_MODIFIER:
+ {
+ if (index.column() == FILE_COLUMN_MODIFIER) {
+ text = model->data(index, Qt::DisplayRole).toString();
+ }
+ QFont font = model->data(index, Qt::FontRole).value<QFont>();
+ QRect rect(option_rect.topLeft() + QPoint(9, -2), size - QSize(10, 0));
+ painter->save();
+ painter->setPen(kFontColor);
+ painter->setFont(font);
+ painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, text);
+ painter->restore();
+ }
+ break;
+ case FILE_COLUMN_PROGRESS:
+ // don't do anything
+ break;
+ default:
+ // never reached here
+ // QStyledItemDelegate::paint(painter, option, index);
+ qWarning() << "invalid item (row)";
+ break;
+ }
+}
+
+FileTableView::FileTableView(QWidget *parent)
+ : QTableView(parent),
+ parent_(qobject_cast<FileBrowserDialog*>(parent)),
+ source_model_(NULL),
+ proxy_model_(NULL)
+{
+ verticalHeader()->hide();
+ verticalHeader()->setDefaultSectionSize(kDefaultColumnHeight);
+ horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+ horizontalHeader()->setStretchLastSection(true);
+ horizontalHeader()->setCascadingSectionResizes(true);
+ horizontalHeader()->setHighlightSections(false);
+ horizontalHeader()->setSortIndicatorShown(true);
+ horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+
+ setGridStyle(Qt::NoPen);
+ setShowGrid(false);
+ setContentsMargins(0, 0, 0, 0);
+ setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ setMouseTracking(true);
+ setDragDropMode(QAbstractItemView::DropOnly);
+ setItemDelegate(new FileTableViewDelegate(this));
+
+ connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+ setupContextMenu();
+}
+
+void FileTableView::setModel(QAbstractItemModel *model)
+{
+ source_model_ = qobject_cast<FileTableModel*>(model);
+ if (!source_model_)
+ return;
+ proxy_model_ = new FileTableSortFilterProxyModel(source_model_);
+ proxy_model_->setSourceModel(source_model_);
+ QTableView::setModel(proxy_model_);
+
+ setColumnHidden(FILE_COLUMN_PROGRESS, true);
+ connect(model, SIGNAL(modelAboutToBeReset()), this, SLOT(onAboutToReset()));
+ setSortingEnabled(true);
+
+ // set default sort by folder
+ sortByColumn(FILE_COLUMN_NAME, Qt::AscendingOrder);
+}
+
+const SeafDirent *FileTableView::getSelectedItemFromSource()
+{
+ QItemSelectionModel *selections = this->selectionModel();
+ QModelIndexList selected = selections->selectedRows();
+ if (selected.size() == 1)
+ return source_model_->direntAt(proxy_model_->mapToSource(selected.front()).row());
+ return NULL;
+}
+
+QList<const SeafDirent *> FileTableView::getSelectedItemsFromSource()
+{
+ QList<const SeafDirent *> results;
+ QItemSelectionModel *selections = this->selectionModel();
+ QModelIndexList selected = selections->selectedRows();
+ results.reserve(selected.size());
+ for (int i = 0; i != selected.size() ; i++) {
+ results.push_back(source_model_->direntAt(proxy_model_->mapToSource(selected[i]).row()));
+ }
+ return results;
+}
+
+void FileTableView::setupContextMenu()
+{
+ context_menu_ = new QMenu(this);
+ connect(parent_, SIGNAL(aboutToClose()),
+ context_menu_, SLOT(close()));
+
+ retry_upload_cached_file_action_ = new QAction(tr("Retry Upload"), this);
+ connect(retry_upload_cached_file_action_, SIGNAL(triggered()),
+ this, SLOT(onRetryUploadCachedFile()));
+ delete_local_version_action_ = new QAction(tr("Delete Local Version"), this);
+ connect(delete_local_version_action_, SIGNAL(triggered()),
+ this, SLOT(onDeleteLocalVersion()));
+ local_version_saveas_action_ = new QAction(tr("Local Version Save As..."), this);
+ connect(local_version_saveas_action_, SIGNAL(triggered()),
+ this, SLOT(onLocalVersionSaveAs()));
+ saveas_action_ = new QAction(tr("&Save As..."), this);
+ connect(saveas_action_, SIGNAL(triggered()),
+ this, SLOT(onSaveAs()));
+ saveas_action_->setShortcut(Qt::ALT + Qt::Key_S);
+
+ lock_action_ = new QAction(tr("&Lock"), this);
+ connect(lock_action_, SIGNAL(triggered()), this, SLOT(onLock()));
+ lock_action_->setShortcut(Qt::ALT + Qt::Key_L);
+ if (!parent_->account_.isAtLeastProVersion(4, 2, 0)) {
+ lock_action_->setEnabled(false);
+ lock_action_->setToolTip(tr("This feature is available in pro version only\n"));
+ }
+
+ rename_action_ = new QAction(tr("&Rename"), this);
+ connect(rename_action_, SIGNAL(triggered()),
+ this, SLOT(onRename()));
+ rename_action_->setShortcut(Qt::ALT + Qt::Key_R);
+
+ remove_action_ = new QAction(tr("&Delete"), this);
+ connect(remove_action_, SIGNAL(triggered()),
+ this, SLOT(onRemove()));
+ // remove_action_->setShortcut(QKeySequence::Delete);
+
+ share_action_ = new QAction(tr("&Generate %1 Download Link").arg(getBrand()), this);
+ connect(share_action_, SIGNAL(triggered()),
+ this, SLOT(onShare()));
+ share_action_->setShortcut(Qt::ALT + Qt::Key_G);
+
+ upload_link_action_ = new QAction(tr("&Generate %1 Upload Link").arg(getBrand()), this);
+ connect(upload_link_action_, SIGNAL(triggered()),
+ this, SLOT(onGenUploadLink()));
+ upload_link_action_->setShortcut(Qt::ALT + Qt::Key_L);
+
+ share_to_user_action_ = new QAction(tr("Share to User"), this);
+ connect(share_to_user_action_, SIGNAL(triggered()),
+ this, SLOT(onShareToUser()));
+
+ share_to_group_action_ = new QAction(tr("Share to Group"), this);
+ connect(share_to_group_action_, SIGNAL(triggered()),
+ this, SLOT(onShareToGroup()));
+
+ share_seafile_action_ = new QAction(tr("G&enerate %1 Internal Link").arg(getBrand()), this);
+ connect(share_seafile_action_, SIGNAL(triggered()),
+ this, SLOT(onShareSeafile()));
+ share_seafile_action_->setShortcut(Qt::ALT + Qt::Key_E);
+
+ if (parent_->repo_.encrypted) {
+ share_action_->setEnabled(false);
+ upload_link_action_->setEnabled(false);
+ share_to_user_action_->setEnabled(false);
+ share_to_group_action_->setEnabled(false);
+ }
+
+ update_action_ = new QAction(tr("&Update"), this);
+ connect(update_action_, SIGNAL(triggered()), this, SLOT(onUpdate()));
+ update_action_->setShortcut(Qt::ALT + Qt::Key_U);
+
+ copy_action_ = new QAction(tr("&Copy"), this);
+ connect(copy_action_, SIGNAL(triggered()), this, SLOT(onCopy()));
+ copy_action_->setShortcut(QKeySequence::Copy);
+
+ move_action_ = new QAction(tr("Cu&t"), this);
+ connect(move_action_, SIGNAL(triggered()), this, SLOT(onMove()));
+ move_action_->setShortcut(QKeySequence::Cut);
+
+ paste_action_ = new QAction(tr("&Paste"), this);
+ connect(paste_action_, SIGNAL(triggered()), this, SIGNAL(direntPaste()));
+ paste_action_->setShortcut(QKeySequence::Paste);
+
+ if (parent_->current_readonly_) {
+ move_action_->setEnabled(false);
+ paste_action_->setEnabled(false);
+ }
+
+ cancel_download_action_ = new QAction(tr("Canc&el Download"), this);
+ connect(cancel_download_action_, SIGNAL(triggered()),
+ this, SLOT(onCancelDownload()));
+ cancel_download_action_->setShortcut(Qt::ALT + Qt::Key_C);
+
+ sync_subdirectory_action_ = new QAction(tr("&Sync this folder"), this);
+ connect(sync_subdirectory_action_, SIGNAL(triggered()),
+ this, SLOT(onSyncSubdirectory()));
+ // sync_subdirectory_action_->setShortcut(Qt::ALT + Qt::Key_S);
+ if (!parent_->account_.isAtLeastVersion(4, 1, 0)) {
+ sync_subdirectory_action_->setEnabled(false);
+ sync_subdirectory_action_->setToolTip(tr("This feature is available in pro version only\n"));
+ }
+
+ open_local_cache_folder_action_ = new QAction(tr("Open Local Cache Folder"), this);
+ connect(open_local_cache_folder_action_, SIGNAL(triggered()),
+ this, SLOT(onOpenLocalCacheFolder()));
+
+ context_menu_->addAction(retry_upload_cached_file_action_);
+ context_menu_->addAction(delete_local_version_action_);
+ context_menu_->addAction(local_version_saveas_action_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(saveas_action_);
+ context_menu_->addAction(share_action_);
+ context_menu_->addAction(upload_link_action_);
+ context_menu_->addAction(share_seafile_action_);
+ context_menu_->addAction(share_to_user_action_);
+ context_menu_->addAction(share_to_group_action_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(move_action_);
+ context_menu_->addAction(copy_action_);
+ context_menu_->addAction(paste_action_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(lock_action_);
+ context_menu_->addAction(rename_action_);
+ context_menu_->addAction(remove_action_);
+ context_menu_->addSeparator();
+ // context_menu_->addAction(update_action_);
+ context_menu_->addAction(cancel_download_action_);
+ context_menu_->addAction(sync_subdirectory_action_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(open_local_cache_folder_action_);
+
+ this->addAction(retry_upload_cached_file_action_);
+ this->addAction(delete_local_version_action_);
+ this->addAction(local_version_saveas_action_);
+ this->addAction(saveas_action_);
+ this->addAction(share_action_);
+ this->addAction(share_seafile_action_);
+ this->addAction(move_action_);
+ this->addAction(copy_action_);
+ this->addAction(paste_action_);
+ this->addAction(lock_action_);
+ this->addAction(rename_action_);
+ this->addAction(remove_action_);
+ // this->addAction(update_action_);
+ this->addAction(cancel_download_action_);
+ this->addAction(sync_subdirectory_action_);
+ this->addAction(open_local_cache_folder_action_);
+
+ paste_only_menu_ = new QMenu(this);
+ paste_only_menu_->addAction(paste_action_);
+}
+
+void FileTableView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPoint position = event->pos();
+ const QModelIndex proxy_index = indexAt(position);
+ position = viewport()->mapToGlobal(position);
+
+ retry_upload_cached_file_action_->setVisible(false);
+ delete_local_version_action_->setVisible(false);
+ local_version_saveas_action_->setVisible(false);
+ open_local_cache_folder_action_->setEnabled(false);
+
+ //
+ // paste_action shows only if there are files in the clipboard
+ // and is enabled only if it comes from the same account
+ //
+ paste_action_->setVisible(parent_->hasFilesToBePasted());
+
+ //
+ // show paste only menu for no items
+ // paste-dedicated menu
+ //
+ paste_action_->setEnabled(!parent_->current_readonly_ &&
+ parent_->account_to_be_pasted_from_ ==
+ parent_->account_ &&
+ parent_->hasFilesToBePasted());
+ if (!proxy_index.isValid()) {
+ if (parent_->hasFilesToBePasted()) {
+ paste_only_menu_->exec(position);
+ }
+ return;
+ }
+
+ // printf ("paste action enabled: %s\n", paste_action_->isEnabled() ? "true": "false");
+
+ //
+ // map back to the source index from FileTableModel
+ //
+ const QModelIndex index = proxy_model_->mapToSource(proxy_index);
+ const int row = index.row();
+ const SeafDirent *dirent = source_model_->direntAt(row);
+ // if invalid dirent? no sure why it comes
+ if (!dirent)
+ return;
+
+ //
+ // find if the item is in the selection
+ // get selections
+ QItemSelectionModel *selections = this->selectionModel();
+ QModelIndexList selected = selections->selectedRows();
+ int pos;
+ for (pos = 0; pos < selected.size(); pos++)
+ {
+ if (row == proxy_model_->mapToSource(selected[pos]).row())
+ break;
+ }
+ //
+ // if the item is in the selection
+ // but it is a multi-selection
+ //
+ // the situation is different from the single-selection
+ // supports: download only (and cancel download action perhaps?)
+ //
+ if (pos != selected.size() && selected.size() != 1) {
+ item_.reset(NULL);
+
+ bool has_dir = false;
+ for (int i = 0; i != selected.size() ; i++) {
+ if (source_model_->direntAt(proxy_model_->mapToSource(selected[i]).row())->isDir()) {
+ has_dir = true;
+ break;
+ }
+ }
+
+ saveas_action_->setText(tr("&Save As To..."));
+ saveas_action_->setVisible(true);
+ saveas_action_->setEnabled(!has_dir);
+ lock_action_->setVisible(false);
+ rename_action_->setVisible(false);
+ share_action_->setVisible(false);
+ upload_link_action_->setVisible(false);
+ share_seafile_action_->setVisible(false);
+ share_to_user_action_->setVisible(false);
+ share_to_group_action_->setVisible(false);
+ // update_action_->setVisible(false);
+ cancel_download_action_->setVisible(false);
+ sync_subdirectory_action_->setVisible(false);
+
+ context_menu_->exec(position);
+
+ return;
+ }
+
+ //
+ // if the item is not in the selection
+ // and it is the single-selection situation
+ //
+ // it is the most common case
+ //
+
+ item_.reset(new SeafDirent(*dirent));
+
+ saveas_action_->setText(tr("&Save As..."));
+ saveas_action_->setVisible(true);
+ rename_action_->setVisible(true);
+ share_action_->setVisible(true);
+ share_seafile_action_->setVisible(true);
+ // update_action_->setVisible(true);
+ cancel_download_action_->setVisible(true);
+ cancel_download_action_->setVisible(false);
+ if (item_->readonly) {
+ move_action_->setEnabled(false);
+ rename_action_->setEnabled(false);
+ // update_action_->setEnabled(false);
+ remove_action_->setEnabled(false);
+ } else {
+ move_action_->setEnabled(true);
+ rename_action_->setEnabled(true);
+ // update_action_->setEnabled(true);
+ remove_action_->setEnabled(true);
+ }
+
+ if (item_->isDir()) {
+ lock_action_->setVisible(false);
+ // update_action_->setVisible(false);
+ saveas_action_->setEnabled(false);
+ sync_subdirectory_action_->setVisible(true);
+ share_to_user_action_->setVisible(true);
+ share_to_group_action_->setVisible(true);
+ upload_link_action_->setVisible(true);
+ } else {
+ if (item_->locked_by_me) {
+ lock_action_->setText(tr("Un&lock"));
+ lock_action_->setVisible(true);
+ move_action_->setEnabled(true);
+ remove_action_->setEnabled(true);
+ rename_action_->setEnabled(true);
+ } else if (item_->is_locked || item_->readonly) {
+ lock_action_->setVisible(false);
+ move_action_->setEnabled(false);
+ remove_action_->setEnabled(false);
+ rename_action_->setEnabled(false);
+ } else {
+ lock_action_->setText(tr("&Lock"));
+ lock_action_->setVisible(true);
+ move_action_->setEnabled(true);
+ remove_action_->setEnabled(true);
+ rename_action_->setEnabled(true);
+ }
+
+ // update_action_->setVisible(true);
+ saveas_action_->setEnabled(true);
+ sync_subdirectory_action_->setVisible(false);
+ share_to_user_action_->setVisible(false);
+ share_to_group_action_->setVisible(false);
+ upload_link_action_->setVisible(false);
+
+ if (TransferManager::instance()->getDownloadTask(parent_->repo_.id,
+ ::pathJoin(parent_->current_path_, dirent->name))) {
+ cancel_download_action_->setVisible(true);
+ saveas_action_->setVisible(false);
+ }
+ }
+
+ if (!parent_->account_.isPro() ||
+ parent_->repo_.owner != parent_->account_.username) {
+ share_to_user_action_->setVisible(false);
+ share_to_group_action_->setVisible(false);
+ }
+
+ QVariant file_status_v = source_model_->data(index, DirentCacheStatusRole);
+ AutoUpdateManager::FileStatus file_status = (AutoUpdateManager::FileStatus)file_status_v.toInt();
+ if (file_status == AutoUpdateManager::NOT_SYNCED) {
+ retry_upload_cached_file_action_->setVisible(true);
+ delete_local_version_action_->setVisible(true);
+ local_version_saveas_action_->setVisible(true);
+ }
+
+ QString localpath = DataManager::getLocalCacheFilePath(
+ parent_->repo_.id, ::pathJoin(parent_->current_path_, dirent->name));
+ if (QFileInfo(localpath).exists()) {
+ open_local_cache_folder_action_->setEnabled(true);
+ }
+
+ context_menu_->exec(position); // synchronously
+
+ //
+ // reset it to NULL, when the menu exec is done
+ //
+ item_.reset(NULL);
+}
+
+void FileTableView::onAboutToReset()
+{
+ item_.reset(NULL);
+}
+
+void FileTableView::onItemDoubleClicked(const QModelIndex& index)
+{
+ const SeafDirent *dirent =
+ source_model_->direntAt(proxy_model_->mapToSource(index).row());
+
+ if (dirent == NULL)
+ return;
+
+ emit direntClicked(*dirent);
+}
+
+void FileTableView::onRetryUploadCachedFile()
+{
+ const SeafDirent *dirent = getSelectedItemFromSource();
+ parent_->onGetDirentReupload(*dirent);
+}
+
+void FileTableView::onDeleteLocalVersion()
+{
+ const SeafDirent *dirent = getSelectedItemFromSource();
+
+ if (dirent == NULL) {
+ return;
+ }
+
+ emit deleteLocalVersion(*dirent);
+}
+
+void FileTableView::onLocalVersionSaveAs()
+{
+ const SeafDirent *dirent = getSelectedItemFromSource();
+
+ if (dirent == NULL) {
+ return;
+ }
+
+ emit localVersionSaveAs(*dirent);
+}
+
+void FileTableView::onSaveAs()
+{
+ if (item_ == NULL) {
+ const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+ emit direntSaveAs(dirents);
+ return;
+ }
+
+ QList<const SeafDirent*> dirents;
+ dirents.push_back(item_.data());
+ emit direntSaveAs(dirents);
+}
+
+void FileTableView::onLock()
+{
+ const SeafDirent * item = item_.data();
+ if (item == NULL)
+ item = getSelectedItemFromSource();
+ if (!item || item->isDir() || item->readonly)
+ return;
+
+ emit direntLock(*item);
+}
+
+void FileTableView::onRename()
+{
+ if (item_ == NULL) {
+ const SeafDirent *selected_item = getSelectedItemFromSource();
+ if (selected_item && !selected_item->readonly)
+ emit direntRename(*selected_item);
+ return;
+ }
+
+ if (!item_->readonly)
+ emit direntRename(*item_);
+}
+
+void FileTableView::onRemove()
+{
+ bool has_readonly = false;
+ if (item_ == NULL) {
+ const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+ Q_FOREACH(const SeafDirent* dirent, dirents)
+ {
+ if (dirent->readonly) {
+ has_readonly = true;
+ break;
+ }
+ }
+ if (!has_readonly) {
+ emit direntRemove(dirents);
+ return;
+ }
+ }
+ if (has_readonly || item_->readonly) {
+ seafApplet->messageBox(tr("Unable to remove readonly files"), this);
+ }
+
+ emit direntRemove(*item_);
+}
+
+void FileTableView::onShare()
+{
+ if (item_ == NULL) {
+ const SeafDirent *selected_item = getSelectedItemFromSource();
+ if (selected_item && selected_item->isFile())
+ emit direntShare(*selected_item);
+ return;
+ }
+ emit direntShare(*item_);
+}
+
+void FileTableView::onGenUploadLink()
+{
+ if (item_ == NULL) {
+ const SeafDirent *selected_item = getSelectedItemFromSource();
+ if (selected_item && selected_item->isDir())
+ emit direntUploadLink(*selected_item);
+ return;
+ }
+ emit direntUploadLink(*item_);
+}
+
+void FileTableView::onShareToUser()
+{
+ onShareToUserOrGroup(false);
+}
+
+void FileTableView::onShareToGroup()
+{
+ onShareToUserOrGroup(true);
+}
+
+void FileTableView::onShareToUserOrGroup(bool to_group)
+{
+ if (item_ == NULL) {
+ const SeafDirent *selected_item = getSelectedItemFromSource();
+ if (selected_item && selected_item->isDir())
+ emit direntShareToUserOrGroup(*selected_item, to_group);
+ return;
+ }
+ emit direntShareToUserOrGroup(*item_, to_group);
+}
+
+
+void FileTableView::onShareSeafile()
+{
+ if (item_ == NULL) {
+ const SeafDirent *selected_item = getSelectedItemFromSource();
+ if (selected_item && selected_item->isFile())
+ emit direntShareSeafile(*selected_item);
+ return;
+ }
+ emit direntShareSeafile(*item_);
+}
+
+
+void FileTableView::onUpdate()
+{
+ if (item_ == NULL) {
+ const SeafDirent *selected_item = getSelectedItemFromSource();
+ if (selected_item && selected_item->isFile() && !selected_item->readonly)
+ emit direntUpdate(*selected_item);
+ return;
+ }
+ if (!item_->readonly)
+ emit direntUpdate(*item_);
+}
+
+void FileTableView::onCopy()
+{
+ QMap<QString, int> file_names;
+
+ if (item_ == NULL) {
+ const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+ for (int i = 0; i < dirents.size(); i++) {
+ file_names.insert(dirents[i]->name, dirents[i]->type == SeafDirent::DIR ? 1 : 0);
+ }
+ } else {
+ file_names.insert(item_->name, item_->type == SeafDirent::DIR ? 1 : 0);
+ }
+
+ parent_->setFilesToBePasted(true, file_names);
+}
+
+void FileTableView::onMove()
+{
+ QMap<QString, int> file_names;
+ bool has_readonly = false;
+
+ if (item_ == NULL) {
+ const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+ for (int i = 0; i < dirents.size(); i++) {
+ // unable to move readonly files
+ if (dirents[i]->readonly) {
+ has_readonly = true;
+ break;
+ }
+ file_names.insert(dirents[i]->name, dirents[i]->type == SeafDirent::DIR ? 1 : 0);
+ }
+ } else {
+ if (item_->readonly) {
+ has_readonly = true;
+ } else {
+ file_names.insert(item_->name, item_->type == SeafDirent::DIR ? 1 : 0);
+ }
+ }
+
+ if (has_readonly) {
+ seafApplet->messageBox(tr("Unable to cut readonly files"), this);
+ return;
+ }
+
+ parent_->setFilesToBePasted(false, file_names);
+}
+
+void FileTableView::onCancelDownload()
+{
+ if (item_ == NULL) {
+ const QList<const SeafDirent*> dirents = getSelectedItemsFromSource();
+ for (int i = 0; i < dirents.size(); i++) {
+ emit cancelDownload(*dirents[i]);
+ }
+ return;
+ }
+ emit cancelDownload(*item_);
+}
+
+void FileTableView::onSyncSubdirectory()
+{
+ if (item_ && item_->isDir())
+ emit syncSubdirectory(item_->name);
+}
+
+void FileTableView::onOpenLocalCacheFolder()
+{
+ parent_->onOpenLocalCacheFolder();
+}
+
+void FileTableView::resizeEvent(QResizeEvent *event)
+{
+ QTableView::resizeEvent(event);
+ if (source_model_)
+ source_model_->onResize(event->size());
+}
+
+FileTableModel::FileTableModel(QObject *parent)
+ : QAbstractTableModel(parent),
+ name_column_width_(kFileNameColumnWidth)
+{
+ task_progress_timer_ = new QTimer(this);
+ connect(task_progress_timer_, SIGNAL(timeout()),
+ this, SLOT(updateDownloadInfo()));
+ connect(task_progress_timer_, SIGNAL(timeout()),
+ this, SLOT(updateFileCacheStatus()));
+ connect(ThumbnailService::instance(), SIGNAL(thumbnailUpdated(const QPixmap&, const QString&)),
+ this, SLOT(updateThumbnail(const QPixmap &, const QString&)));
+ task_progress_timer_->start(kRefreshProgressInterval);
+}
+
+void FileTableModel::setDirents(const QList<SeafDirent>& dirents)
+{
+ beginResetModel();
+ dirents_ = dirents;
+ progresses_.clear();
+ file_cache_statuses_.clear();
+ endResetModel();
+
+ updateFileCacheStatus();
+ updateDownloadInfo();
+ task_progress_timer_->start();
+}
+
+int FileTableModel::rowCount(const QModelIndex& parent) const
+{
+ return dirents_.size();
+}
+
+int FileTableModel::columnCount(const QModelIndex& parent) const
+{
+ return FILE_MAX_COLUMN;
+}
+
+QVariant FileTableModel::data(const QModelIndex & index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ const int column = index.column();
+ const int row = index.row();
+ const SeafDirent& dirent = dirents_[row];
+
+ if (role == Qt::DecorationRole && column == FILE_COLUMN_NAME) {
+ QIcon icon;
+
+ // These are the thumnail types supported by the server (as of 2019.1)
+ static QSet<QString> image_file_types = {"gif", "png", "jpg", "jpeg", "ico"};
+ if (dirent.isDir()) {
+ icon = dirent.readonly
+ ? QIcon(":/images/files_v2/file_folder_readonly.png")
+ : QIcon(":/images/files_v2/file_folder.png");
+ } else if (image_file_types.contains(QFileInfo(dirent.name).suffix().toLower())) {
+ FileBrowserDialog *dialog =
+ (FileBrowserDialog *)(QObject::parent());
+ ThumbnailService *service = ThumbnailService::instance();
+ return service->getThumbnail(
+ dialog->repo_.id,
+ ::pathJoin(dialog->current_path_, dirent.name),
+ dirent.id,
+ kColumnIconSize * globalDevicePixelRatio());
+ } else {
+ icon = QIcon(getIconByFileNameV2(dirent.name));
+ }
+ return icon.pixmap(kColumnIconSize, kColumnIconSize);
+ }
+
+ if (role == Qt::SizeHintRole) {
+ QSize qsize(kDefaultColumnWidth, kDefaultColumnHeight);
+ switch (column) {
+ case FILE_COLUMN_NAME:
+ qsize.setWidth(name_column_width_);
+ break;
+ case FILE_COLUMN_PROGRESS:
+ case FILE_COLUMN_SIZE:
+ case FILE_COLUMN_MTIME:
+ qsize.setWidth(name_column_width_);
+ case FILE_COLUMN_MODIFIER:
+ default:
+ break;
+ }
+ return qsize;
+ }
+
+ if (role == DirentLockStatusRole && column == FILE_COLUMN_NAME) {
+ if (dirent.locked_by_me) {
+ return (int)LOCKED_BY_ME;
+ } else if (dirent.is_locked) {
+ return (int)LOCKED_BY_OTHERS;
+ } else
+ return NOT_LOCKED;
+ }
+
+ if (role == DirentLockOwnerRole && column == FILE_COLUMN_NAME) {
+ return dirent.lock_owner;
+ }
+
+ if (role == Qt::ToolTipRole && column == FILE_COLUMN_NAME && !dirent.lock_owner.isEmpty()) {
+ return tr("locked by %1").arg(dirent.getLockOwnerDisplayString());
+ }
+
+ if (role == DirentCacheStatusRole) {
+ return file_cache_statuses_.contains(dirent.name)
+ ? (int)file_cache_statuses_[dirent.name]
+ : QVariant();
+ }
+
+ if (role != Qt::DisplayRole) {
+ return QVariant();
+ }
+
+ // DisplayRole
+
+ switch (column) {
+ case FILE_COLUMN_NAME:
+ return dirent.name;
+ case FILE_COLUMN_SIZE:
+ if (dirent.isDir())
+ return "";
+ return dirent.size;
+ case FILE_COLUMN_MTIME:
+ return dirent.mtime;
+ case FILE_COLUMN_MODIFIER:
+ return dirent.isDir() ? "" : dirent.modifier_name;
+ case FILE_COLUMN_PROGRESS:
+ return getTransferProgress(dirent);
+ default:
+ return QVariant();
+ }
+}
+
+QString FileTableModel::getTransferProgress(const SeafDirent& dirent) const
+{
+ return progresses_[dirent.name];
+}
+
+QVariant FileTableModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Vertical) {
+ return QVariant();
+ }
+
+ if (role == Qt::TextAlignmentRole) {
+ return Qt::AlignLeft + Qt::AlignVCenter;
+ }
+
+ if (role == Qt::DisplayRole) {
+ switch (section) {
+ case FILE_COLUMN_NAME:
+ return tr("Name");
+ case FILE_COLUMN_SIZE:
+ return tr("Size");
+ case FILE_COLUMN_MTIME:
+ return tr("Last Modified");
+ case FILE_COLUMN_MODIFIER:
+ return tr("Modifier");
+ default:
+ return QVariant();
+ }
+ }
+
+ if (role == Qt::FontRole) {
+ QFont font;
+ font.setPixelSize(12);
+ return font;
+ }
+
+ if (role == Qt::ForegroundRole) {
+ return QBrush(kFontColor);
+ }
+
+ if (role == Qt::SizeHintRole && section == FILE_COLUMN_NAME) {
+ if (dirents_.empty()) {
+ return QSize(name_column_width_, 0);
+ }
+ }
+
+ return QVariant();
+}
+
+const SeafDirent* FileTableModel::direntAt(int row) const
+{
+ if (row >= dirents_.size())
+ return NULL;
+
+ return &dirents_[row];
+}
+
+void FileTableModel::replaceItem(const QString &name, const SeafDirent &dirent)
+{
+ for (int pos = 0; pos != dirents_.size() ; pos++)
+ if (dirents_[pos].name == name) {
+ dirents_[pos] = dirent;
+ emit dataChanged(index(pos, 0), index(pos , FILE_MAX_COLUMN - 1));
+ break;
+ }
+}
+
+void FileTableModel::insertItem(int pos, const SeafDirent &dirent)
+{
+ if (pos > dirents_.size())
+ return;
+ beginInsertRows(QModelIndex(), pos, pos);
+ dirents_.insert(pos, dirent);
+ endInsertRows();
+}
+
+void FileTableModel::removeItemNamed(const QString &name)
+{
+ for (int pos = 0; pos != dirents_.size() ; pos++)
+ if (dirents_[pos].name == name) {
+ beginRemoveRows(QModelIndex(), pos, pos);
+ dirents_.removeAt(pos);
+ endRemoveRows();
+ break;
+ }
+}
+
+void FileTableModel::renameItemNamed(const QString &name, const QString &new_name)
+{
+ for (int pos = 0; pos != dirents_.size() ; pos++)
+ if (dirents_[pos].name == name) {
+ dirents_[pos].name = new_name;
+ emit dataChanged(index(pos, 0), index(pos , FILE_MAX_COLUMN - 1));
+ break;
+ }
+}
+
+void FileTableModel::onResize(const QSize &size)
+{
+ name_column_width_ = size.width() - kDefaultColumnSum + kFileNameColumnWidth;
+ // name_column_width_ should be always larger than kFileNameColumnWidth
+ if (dirents_.empty())
+ return;
+ emit dataChanged(index(0, FILE_COLUMN_NAME),
+ index(dirents_.size()-1 , FILE_COLUMN_NAME));
+}
+
+void FileTableModel::updateDownloadInfo()
+{
+ FileBrowserDialog *dialog = (FileBrowserDialog *)(QObject::parent());
+ QList<FileDownloadTask*> tasks= TransferManager::instance()->getDownloadTasks(
+ dialog->repo_.id, dialog->current_path_);
+
+ progresses_.clear();
+
+ Q_FOREACH (FileDownloadTask *task, tasks) {
+ QString progress = task->progress().toString();
+ progresses_[::getBaseName(task->path())] = progress;
+ }
+
+ if (dirents_.empty())
+ return;
+ emit dataChanged(index(0, FILE_COLUMN_SIZE),
+ index(dirents_.size() - 1 , FILE_COLUMN_SIZE));
+}
+
+
+void FileTableModel::updateFileCacheStatus()
+{
+ if (dirents_.empty())
+ return;
+
+ FileBrowserDialog *dialog = (FileBrowserDialog *)(QObject::parent());
+ QHash<QString, AutoUpdateManager::FileStatus> new_statues =
+ AutoUpdateManager::instance()->getFileStatusForDirectory(
+ dialog->account_.getSignature(),
+ dialog->repo_.id,
+ dialog->current_path_,
+ dirents_);
+
+ if (new_statues == file_cache_statuses_) {
+ return;
+ }
+
+ for (int pos = 0; pos != dirents_.size() ; pos++) {
+ const QString& name = dirents_[pos].name;
+ int new_status = new_statues.contains(name) ? (int)new_statues[name] : -1;
+ int old_status = file_cache_statuses_.contains(name) ? (int)file_cache_statuses_[name] : -1;
+ if (new_status != old_status) {
+ emit dataChanged(index(pos, FILE_COLUMN_NAME), index(pos , FILE_COLUMN_NAME));
+ }
+ }
+
+ file_cache_statuses_ = new_statues;
+ // printf ("repainting when file cache status is changed\n");
+ // emit dataChanged(index(0, FILE_COLUMN_NAME),
+ // index(dirents_.size() - 1 , FILE_COLUMN_NAME));
+}
+
+void FileTableModel::updateThumbnail(const QPixmap& thumbnail, const QString& path)
+{
+ const QString name = QFileInfo(path).fileName();
+ for (int pos = 0; pos != dirents_.size() ; pos++)
+ if (dirents_[pos].name == name) {
+ emit dataChanged(index(pos, 0), index(pos, FILE_COLUMN_NAME));
+ break;
+ }
+}
+
+bool FileTableSortFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
+{
+ bool is_dir_left = source_model_->direntAt(left.row())->isDir();
+ bool is_dir_right = source_model_->direntAt(right.row())->isDir();
+ if (is_dir_left != is_dir_right) {
+ return sortOrder() != Qt::AscendingOrder ? is_dir_right
+ : !is_dir_right;
+ }
+ else if ((left.column() == FILE_COLUMN_NAME) &&
+ (right.column() == FILE_COLUMN_NAME)) {
+ const QString left_name = source_model_->direntAt(left.row())->name;
+ const QString right_name = source_model_->direntAt(right.row())->name;
+ return digitalCompare(left_name, right_name) < 0;
+ }
+ else {
+ return QSortFilterProxyModel::lessThan(left, right);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_TABLE_H
+#define SEAFILE_CLIENT_FILE_TABLE_H
+
+#include <QTableView>
+#include <QStandardItem>
+#include <QAbstractTableModel>
+#include <QStyledItemDelegate>
+#include <QModelIndex>
+#include <QScopedPointer>
+#include <QSortFilterProxyModel>
+
+#include "api/server-repo.h"
+#include "seaf-dirent.h"
+#include "auto-update-mgr.h"
+
+#include "thumbnail-service.h"
+
+class DataManager;
+class ThumbnailService;
+
+class FileTableViewDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+public:
+ FileTableViewDelegate(QObject *parent);
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+class FileBrowserDialog;
+class FileTableModel;
+class FileTableView : public QTableView
+{
+ Q_OBJECT
+public:
+ FileTableView(QWidget *parent);
+ void setModel(QAbstractItemModel *model);
+
+signals:
+ void direntClicked(const SeafDirent& dirent);
+ void direntSaveAs(const QList<const SeafDirent*> &dirents);
+ void deleteLocalVersion(const SeafDirent& dirent);
+ void localVersionSaveAs(const SeafDirent& dirent);
+ void dropFile(const QStringList& paths);
+ void direntLock(const SeafDirent& dirent);
+ void direntRename(const SeafDirent& dirent);
+ void direntRemove(const SeafDirent& dirent);
+ void direntRemove(const QList<const SeafDirent*> &dirents);
+ void direntUpdate(const SeafDirent& dirent);
+ void direntShare(const SeafDirent& dirent);
+ void direntShareToUserOrGroup(const SeafDirent& dirent, bool to_group);
+ void direntShareSeafile(const SeafDirent& dirent);
+ void direntUploadLink(const SeafDirent& dirent);
+ void direntPaste();
+
+ void cancelDownload(const SeafDirent& dirent);
+ void syncSubdirectory(const QString& folder_name);
+
+private slots:
+ void onAboutToReset();
+ void onItemDoubleClicked(const QModelIndex& index);
+ void onRetryUploadCachedFile();
+ void onDeleteLocalVersion();
+ void onLocalVersionSaveAs();
+ void onSaveAs();
+ void onLock();
+ void onRename();
+ void onRemove();
+ void onShare();
+ void onGenUploadLink();
+ void onShareToUser();
+ void onShareToGroup();
+ void onShareSeafile();
+ void onUpdate();
+ void onCopy();
+ void onMove();
+
+ void onCancelDownload();
+ void onSyncSubdirectory();
+ void onOpenLocalCacheFolder();
+
+private:
+ void setupContextMenu();
+
+ // \brief get current selection item
+ // it returns non-NULL if only we have one and only one item in seleceted
+ // the index it uses internally is mapped to source model
+ const SeafDirent *getSelectedItemFromSource();
+
+ // \brief get current selection items
+ // it returns the list of all of selected SeafDirents
+ // the indexes it uses internally is mapped to source model
+ QList<const SeafDirent *> getSelectedItemsFromSource();
+ void contextMenuEvent(QContextMenuEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ void onShareToUserOrGroup(bool to_group);
+
+ Q_DISABLE_COPY(FileTableView)
+
+ // \brief the copy of the exact item where right click event occurs
+ // its lifetime is valid during the menu event and exec and invalid outside
+ QScopedPointer<const SeafDirent> item_;
+ QMenu *context_menu_;
+ QMenu *paste_only_menu_;
+ QAction *retry_upload_cached_file_action_;
+ QAction *delete_local_version_action_;
+ QAction *local_version_saveas_action_;
+ QAction *saveas_action_;
+ QAction *rename_action_;
+ QAction *remove_action_;
+ QAction *share_action_;
+ QAction *upload_link_action_;
+ QAction *share_to_user_action_;
+ QAction *share_to_group_action_;
+ QAction *share_seafile_action_;
+ QAction *update_action_;
+ QAction *copy_action_;
+ QAction *move_action_;
+ QAction *paste_action_;
+ QAction *cancel_download_action_;
+ QAction *sync_subdirectory_action_;
+ QAction *lock_action_;
+ QAction *open_local_cache_folder_action_;
+ FileBrowserDialog *parent_;
+
+ // source model
+ FileTableModel *source_model_;
+ // proxy model
+ QSortFilterProxyModel *proxy_model_;
+};
+
+class FileTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ FileTableModel(QObject *parent=0);
+
+ int rowCount(const QModelIndex& parent=QModelIndex()) const;
+ int columnCount(const QModelIndex& parent=QModelIndex()) const;
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ void setDirents(const QList<SeafDirent>& dirents);
+ const QList<SeafDirent>& dirents() const { return dirents_; }
+
+ const SeafDirent* direntAt(int row) const;
+
+ void insertItem(int pos, const SeafDirent &dirent);
+ void appendItem(const SeafDirent &dirent) {
+ insertItem(rowCount(), dirent);
+ }
+ void replaceItem(const QString &name, const SeafDirent &dirent);
+ void removeItemNamed(const QString &name);
+ void renameItemNamed(const QString &name, const QString &new_name);
+
+ void onResize(const QSize &size);
+
+private slots:
+ void updateDownloadInfo();
+ void updateFileCacheStatus();
+ void updateThumbnail(const QPixmap& thumbnail, const QString& file_path);
+
+private:
+ Q_DISABLE_COPY(FileTableModel)
+
+ QString getTransferProgress(const SeafDirent& dirent) const;
+
+ QList<SeafDirent> dirents_;
+
+ QHash<QString, QString> progresses_;
+ QHash<QString, AutoUpdateManager::FileStatus> file_cache_statuses_;
+
+ int name_column_width_;
+
+ QTimer *task_progress_timer_;
+};
+
+class FileTableSortFilterProxyModel : public QSortFilterProxyModel {
+ Q_OBJECT
+public:
+ FileTableSortFilterProxyModel(FileTableModel *parent)
+ : QSortFilterProxyModel(parent), source_model_(parent) {
+ setSortCaseSensitivity(Qt::CaseInsensitive);
+ }
+ bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
+
+private:
+ FileTableModel* source_model_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_TABLE_H
--- /dev/null
+#include <QMessageBox>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QProgressBar>
+#include <QPushButton>
+#include <QDesktopServices>
+#include <QDebug>
+#include <climits>
+
+#include "utils/utils.h"
+#include "progress-dialog.h"
+#include "seafile-applet.h"
+#include "transfer-mgr.h"
+
+namespace
+{
+const char* kQueryIndexUrl = "idx_progress";
+} // namespace
+
+
+FileBrowserProgressDialog::FileBrowserProgressDialog(FileNetworkTask *task, QWidget *parent)
+ : QProgressDialog(parent),
+ task_(task),
+ progress_request_(NULL),
+ index_progress_timer_(new QTimer(this)),
+ task_finished_(false)
+{
+ initUI();
+ initTaskInfo();
+
+ connect(index_progress_timer_, SIGNAL(timeout()), this, SLOT(onQueryUpdate()));
+
+ connect(task_, SIGNAL(progressUpdate(qint64, qint64)),
+ this, SLOT(onProgressUpdate(qint64, qint64)));
+ connect(task_, SIGNAL(nameUpdate(QString)),
+ this, SLOT(onCurrentNameUpdate(QString)));
+ connect(task_, SIGNAL(finished(bool)), this, SLOT(onTaskFinished(bool)));
+ connect(task_, SIGNAL(retried(int)), this, SLOT(initTaskInfo()));
+ connect(this, SIGNAL(canceled()), this, SLOT(cancel()));
+
+ if (task_->type() == FileNetworkTask::Upload) {
+ FileUploadTask *upload_task = (FileUploadTask *)task_;
+ connect(upload_task, SIGNAL(oneFileFailed(const QString&, bool)),
+ this, SLOT(onOneFileUploadFailed(const QString&, bool)));
+ }
+}
+
+void FileBrowserProgressDialog::initUI()
+{
+ setWindowModality(Qt::NonModal);
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ QVBoxLayout *layout_ = new QVBoxLayout;
+ progress_bar_ = new QProgressBar;
+ description_label_ = new QLabel;
+
+ layout_->addWidget(description_label_);
+ layout_->addWidget(progress_bar_);
+
+ QHBoxLayout *hlayout_ = new QHBoxLayout;
+ more_details_label_ = new QLabel;
+ more_details_label_->setText(tr("Pending"));
+ cancel_button_ = new QPushButton(tr("Cancel"));
+ QWidget *spacer = new QWidget;
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ hlayout_->addWidget(more_details_label_);
+ hlayout_->addWidget(spacer);
+ hlayout_->addWidget(cancel_button_);
+ hlayout_->setContentsMargins(-1, 0, -1, 6);
+ layout_->setContentsMargins(-1, 0, -1, 6);
+ layout_->addLayout(hlayout_);
+
+ setLayout(layout_);
+ setLabel(description_label_);
+ setBar(progress_bar_);
+ setCancelButton(cancel_button_);
+}
+
+FileBrowserProgressDialog::~FileBrowserProgressDialog()
+{
+ if (progress_request_ != NULL)
+ progress_request_->deleteLater();
+}
+
+void FileBrowserProgressDialog::initTaskInfo()
+{
+ task_finished_ = false;
+ if (task_->canceled()) {
+ return;
+ }
+ QString title, label;
+ if (task_->type() == FileNetworkTask::Upload) {
+ title = tr("Upload");
+ label = tr("Uploading %1");
+ } else {
+ title = tr("Download");
+ label = tr("Downloading %1");
+ }
+ setWindowTitle(title);
+ setLabelText(label.arg(QFileInfo(task_->localFilePath()).fileName()));
+
+ more_details_label_->setText("");
+
+ setMaximum(0);
+ setValue(0);
+}
+
+void FileBrowserProgressDialog::onCurrentNameUpdate(QString current_name)
+{
+ QString label = tr("Uploading %1");
+ setLabelText(label.arg(current_name));
+}
+
+void FileBrowserProgressDialog::onProgressUpdate(qint64 processed_bytes, qint64 total_bytes)
+{
+ // Skip the updates if the task has been cancelled, because we may already
+ // have already rejected this dialog.
+ if (task_->canceled()) {
+ return;
+ }
+ // if the value is less than the maxmium, this dialog will close itself
+ // add this guard for safety
+ if (processed_bytes >= total_bytes)
+ total_bytes = processed_bytes + 1;
+
+ if (total_bytes > INT_MAX) {
+ if (maximum() != INT_MAX)
+ setMaximum(INT_MAX);
+
+ // Avoid overflow
+ double progress = double(processed_bytes) * INT_MAX / total_bytes;
+ setValue((int)progress);
+ } else {
+ if (maximum() != total_bytes)
+ setMaximum(total_bytes);
+
+ setValue(processed_bytes);
+ }
+
+ more_details_label_->setText(tr("%1 of %2")
+ .arg(::readableFileSizeV2(processed_bytes))
+ .arg(::readableFileSizeV2(total_bytes)));
+}
+
+void FileBrowserProgressDialog::onTaskFinished(bool success)
+{
+ task_finished_ = true;
+ // printf ("FileBrowserProgressDialog: onTaskFinished\n");
+ if (task_->canceled()) {
+ return;
+ }
+
+ cancel_button_->setVisible(false);
+
+ // When this "onTaskFinished" slot is called, the task may NOT
+ // have really finished yet, i.e. if we configured "async save" on
+ // server, we need to query the async save progress and only close
+ // the dialog after the async save is done.
+ //
+ // TODO: Right now the async save progress query is implemented
+ // here, but ideally it should be implemented inside the
+ // ReliablePostFileTask class for better encapsulation.
+ progerss_id_ = task_->oid();
+
+ //https://dev.seafile.com/seafhttp/upload-api/b7443978-42cf-4cc6-87bf-add0fc7ad6e3
+ //https://dev.seafile.com/seafhttp/idx_progress
+ progress_url_ = ::urlJoin(QUrl(task_->url().toString(QUrl::PrettyDecoded).
+ section("upload", 0, 0)), kQueryIndexUrl);
+ if (success) {
+ // printf ("progress dialog: task success\n");
+
+ //Judge "-" as a task id or a file id
+ //Compatible with new and old server versions
+ if (progerss_id_.contains("-")) {
+ onQueryUpdate();
+ index_progress_timer_->start(3000);
+ } else {
+ accept();
+ }
+ } else {
+ // printf ("progress dialog: task failed\n");
+ reject();
+ }
+}
+
+void FileBrowserProgressDialog::onQueryUpdate()
+{
+ if (progress_request_) {
+ progress_request_->deleteLater();
+ progress_request_ = NULL;
+ }
+
+ progress_request_ = new GetIndexProgressRequest(progress_url_, progerss_id_);
+ connect(progress_request_, SIGNAL(success(const ServerIndexProgress&)),
+ this, SLOT(onQuerySuccess(const ServerIndexProgress&)));
+ connect(progress_request_, SIGNAL(failed(const ApiError& error)),
+ this, SLOT(onQueryFailed(const ApiError& error)));
+
+ progress_request_->send();
+}
+
+void FileBrowserProgressDialog::onQuerySuccess(const ServerIndexProgress &result)
+{
+ setLabelText(tr("Saving"));
+ more_details_label_->setText(tr("%1 of %2")
+ .arg(::readableFileSizeV2(result.indexed))
+ .arg(::readableFileSizeV2(result.total)));
+ if (result.status == 0) {
+ index_progress_timer_->stop();
+ accept();
+ } else if (result.status == -1) {
+ index_progress_timer_->stop();
+ seafApplet->warningBox(tr("File save failed"), this);
+ reject();
+ }
+}
+
+void FileBrowserProgressDialog::onQueryFailed(const ApiError& error)
+{
+ qWarning("get index progress request error: %s", error.toString().toUtf8().data());
+ // when http error occur stop index_progress_timer.
+ if (error.type() == ApiError::HTTP_ERROR) {
+ index_progress_timer_->stop();
+ seafApplet->warningBox(tr("Index progress request error %1").arg(error.httpErrorCode()));
+ reject();
+ }
+}
+
+void FileBrowserProgressDialog::cancel()
+{
+ if (task_finished_ || task_->canceled()) {
+ return;
+ }
+ if (task_->type() == FileNetworkTask::Upload) {
+ task_->cancel();
+ } else {
+ // For download tasks we need to go through the transfer manager
+ TransferManager::instance()->cancelDownload(task_->repoId(), task_->path());
+ }
+ reject();
+}
+
+void FileBrowserProgressDialog::onOneFileUploadFailed(const QString &filename,
+ bool single_file)
+{
+ if (task_->canceled()) {
+ return;
+ }
+
+ FileUploadTask *upload_task = (FileUploadTask *)task_;
+
+ QString msg =
+ tr("Failed to upload file \"%1\", do you want to retry?").arg(filename);
+ ActionOnFailure choice = retryOrSkipOrAbort(msg, single_file);
+
+ switch (choice) {
+ case ActionRetry:
+ upload_task->continueWithFailedFile(true);
+ break;
+ case ActionSkip:
+ upload_task->continueWithFailedFile(false);
+ break;
+ case ActionAbort:
+ cancel();
+ break;
+ }
+}
+
+FileBrowserProgressDialog::ActionOnFailure
+FileBrowserProgressDialog::retryOrSkipOrAbort(const QString& msg, bool single_file)
+{
+ QMessageBox box(this);
+ box.setText(msg);
+ box.setWindowTitle(getBrand());
+ box.setIcon(QMessageBox::Question);
+
+ QPushButton *yes_btn = box.addButton(tr("Retry"), QMessageBox::YesRole);
+ QPushButton *no_btn = nullptr;
+ if (!single_file) {
+ // If this is single file upload/update, we only show "retry" and
+ // "abort".
+ no_btn = box.addButton(tr("Skip"), QMessageBox::NoRole);
+ }
+ box.addButton(tr("Abort"), QMessageBox::RejectRole);
+
+
+ box.setDefaultButton(yes_btn);
+ box.exec();
+ QAbstractButton *btn = box.clickedButton();
+ if (btn == yes_btn) {
+ return ActionRetry;
+ } else if (btn == no_btn) {
+ return ActionSkip;
+ }
+
+ return ActionAbort;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_PROGRESS_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_PROGRESS_DIALOG_H
+
+#include <QProgressDialog>
+#include <QObject>
+#include <QTimer>
+
+#include "tasks.h"
+
+class QProgressBar;
+class QLabel;
+
+
+class FileBrowserProgressDialog : public QProgressDialog {
+ Q_OBJECT
+public:
+ FileBrowserProgressDialog(FileNetworkTask *task, QWidget *parent=0);
+ ~FileBrowserProgressDialog();
+
+ typedef enum {
+ ActionRetry = 0,
+ ActionSkip,
+ ActionAbort,
+ } ActionOnFailure;
+
+public slots:
+ void cancel();
+
+private slots:
+ void onProgressUpdate(qint64 processed_bytes, qint64 total_bytes);
+ void onCurrentNameUpdate(QString current_name);
+ void onTaskFinished(bool success);
+ void initTaskInfo();
+ void onOneFileUploadFailed(const QString& filename, bool single_file);
+ void onQueryUpdate();
+ void onQuerySuccess(const ServerIndexProgress& result);
+ void onQueryFailed(const ApiError& error);
+ ActionOnFailure retryOrSkipOrAbort(const QString& msg, bool single_file);
+
+private:
+ void initUI();
+
+ FileNetworkTask* task_;
+ QPushButton *cancel_button_;
+ QLabel *description_label_;
+ QLabel *more_details_label_;
+ QProgressBar *progress_bar_;
+ QUrl progress_url_;
+ QString progerss_id_;
+ GetIndexProgressRequest *progress_request_;
+ QTimer *index_progress_timer_;
+ bool task_finished_;
+};
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_PROGRESS_DIALOG_H
--- /dev/null
+#include <assert.h>
+
+#include <QBuffer>
+#include <QThread>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QHttpMultiPart>
+#include <QHttpPart>
+#include <QFile>
+#include <QSslError>
+#include <QSslConfiguration>
+#include <QSslCertificate>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "certs-mgr.h"
+#include "api/api-error.h"
+#include "configurator.h"
+#include "network-mgr.h"
+#include "reliable-upload.h"
+
+namespace {
+
+const char *kParentDirParam = "form-data; name=\"parent_dir\"";
+const char *kTargetFileParam = "form-data; name=\"target_file\"";
+const char *kRelativePathParam = "form-data; name=\"relative_path\"";
+const char *kFileParamTemplate = "form-data; name=\"file\"; filename=\"%1\"";
+const char *kContentTypeApplicationOctetStream = "application/octet-stream";
+const char *kFileNameHeaderTemplate = "attachment; filename=\"%1\"";
+
+// 100MB
+const quint32 kMinimalSizeForChunkedUploads = 100 * 1024 * 1024;
+// 1MB
+const quint32 kUploadChunkSize = 1024 * 1024;
+
+// void printThread(const QString& prefix)
+// {
+// printf ("%s %p\n", toCStr(prefix + " "), QThread::currentThreadId());
+// }
+
+} // namesapce
+
+ReliablePostFileTask::ReliablePostFileTask(const Account &account,
+ const QString &repo_id,
+ const QUrl &url,
+ const QString &parent_dir,
+ const QString &local_path,
+ const QString &name,
+ const bool use_upload,
+ const bool accept_user_confirmation)
+ : FileServerTask(url, local_path),
+ account_(account),
+ repo_id_(repo_id),
+ part_of_folder_upload_(false),
+ parent_dir_(parent_dir),
+ file_(nullptr),
+ name_(name),
+ use_upload_(use_upload)
+{
+ current_offset_ = 0;
+ current_chunk_size_ = 0;
+ done_ = 0;
+ total_size_ = 0;
+ // Chunked uploading is disabled for updating an existing file
+ resumable_ = use_upload;
+ accept_user_confirmation_ = accept_user_confirmation;
+}
+
+ReliablePostFileTask::ReliablePostFileTask(const QUrl &url,
+ const QString &parent_dir,
+ const QString &local_path,
+ const QString &name,
+ const QString &relative_path)
+ : FileServerTask(url, local_path),
+ account_(Account()),
+ repo_id_(QString()),
+ part_of_folder_upload_(true),
+ parent_dir_(parent_dir),
+ file_(nullptr),
+ name_(name),
+ use_upload_(true),
+ relative_path_(relative_path)
+{
+ current_offset_ = 0;
+ current_chunk_size_ = 0;
+ done_ = 0;
+ total_size_ = 0;
+ resumable_ = false;
+
+ // This constructor is called by the PostFilesTask, which handles user
+ // confirmation and retry itself.
+ accept_user_confirmation_ = false;
+}
+
+ReliablePostFileTask::~ReliablePostFileTask()
+{
+ if (file_) {
+ file_->close();
+ file_ = nullptr;
+ }
+}
+
+bool ReliablePostFileTask::retryEnabled()
+{
+ return true;
+}
+
+void ReliablePostFileTask::prepare()
+{
+ if (file_) {
+ // In case of retry
+ delete file_;
+ }
+ file_ = new QFile(local_path_);
+ file_->setParent(this);
+ if (!file_->exists()) {
+ setError(FileNetworkTask::FileIOError, tr("File does not exist"));
+ emit finished(false);
+ return;
+ }
+ if (!file_->open(QIODevice::ReadOnly)) {
+ setError(FileNetworkTask::FileIOError, tr("File does not exist"));
+ emit finished(false);
+ return;
+ }
+ total_size_ = file_->size();
+}
+
+bool ReliablePostFileTask::useResumableUpload() const
+{
+ return resumable_ && total_size_ > kMinimalSizeForChunkedUploads;
+}
+
+void ReliablePostFileTask::sendRequest()
+{
+ if (useResumableUpload()) {
+ checkUploadedBytes();
+ } else {
+ startPostFileTask();
+ }
+}
+
+void ReliablePostFileTask::checkUploadedBytes()
+{
+ file_uploaded_bytes_req_.reset(
+ new GetFileUploadedBytesRequest(account_, repo_id_, parent_dir_, name_));
+
+ connect(file_uploaded_bytes_req_.data(), SIGNAL(success(bool, quint64)),
+ this, SLOT(onGetFileUploadedBytesSuccess(bool, quint64)));
+ connect(file_uploaded_bytes_req_.data(), SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetFileUploadedBytesFailed(const ApiError&)));
+ file_uploaded_bytes_req_->send();
+}
+
+void ReliablePostFileTask::onGetFileUploadedBytesSuccess(bool support_chunked_uploading, quint64 uploaded_bytes)
+{
+ if (!support_chunked_uploading) {
+ resumable_ = false;
+ current_offset_ = 0;
+ } else {
+ current_offset_ = uploaded_bytes;
+ }
+
+ startPostFileTask();
+}
+
+void ReliablePostFileTask::onGetFileUploadedBytesFailed(const ApiError& error)
+{
+ resumable_ = false;
+ current_offset_ = 0;
+ // printf("file %s: get uploaded bytes failed with %s\n",
+ // name_.toUtf8().data(),
+ // error.toString().toUtf8().data());
+ startPostFileTask();
+}
+
+void ReliablePostFileTask::startPostFileTask()
+{
+ // Update the progress when retrying
+ emit progressUpdate(current_offset_, total_size_);
+
+ createPostFileTask();
+ QMetaObject::invokeMethod(task_.data(), "start");
+}
+
+void ReliablePostFileTask::createPostFileTask()
+{
+ if (part_of_folder_upload_) {
+ // File uploading as part of directory uploading: does not support
+ // chunked uploads
+ task_.reset(new PostFileTask(url_,
+ parent_dir_,
+ local_path_,
+ file_,
+ name_,
+ relative_path_,
+ total_size_));
+ } else {
+ QUrl url = url_;
+ if (useResumableUpload()) {
+ current_chunk_size_ =
+ qMin((quint64)kUploadChunkSize, total_size_ - current_offset_);
+ // This is a quick fix when the server hasn't implemented chunking
+ // support in /upload/api/ endpoint yet.
+ url = QUrl(url_.toString(QUrl::PrettyDecoded).replace("/upload-api/", "/upload-aj/"));
+ // printf ("old url: %s\n", url_.toEncoded().data());
+ // printf ("new url: %s\n", url.toEncoded().data());
+ need_idx_progress_ = true;
+ } else {
+ need_idx_progress_ = false;
+ }
+ // For emulating upload errors
+ // url = QUrl(url_.toString(QUrl::PrettyDecoded).replace("1", "x").replace("2", "x"));
+ task_.reset(new PostFileTask(url,
+ parent_dir_,
+ local_path_,
+ file_,
+ name_,
+ use_upload_,
+ total_size_,
+ current_offset_,
+ current_chunk_size_,
+ need_idx_progress_));
+ }
+ setupSignals();
+ // printThread("reliable task is in thread");
+ task_.data()->moveToThread(FileNetworkTask::worker_thread_);
+}
+
+void ReliablePostFileTask::setupSignals()
+{
+ connect(task_.data(), SIGNAL(finished(bool)), this, SLOT(onPostFileTaskFinished(bool)));
+ connect(task_.data(),
+ SIGNAL(progressUpdate(qint64, qint64)),
+ this,
+ SLOT(onPostFileTaskProgressUpdate(qint64, qint64)));
+}
+
+void ReliablePostFileTask::handlePostFileTaskFailure()
+{
+ if (!canceled_ && accept_user_confirmation_) {
+ emit oneFileFailed(name_, true);
+ } else {
+ emit finished(false);
+ }
+}
+
+void ReliablePostFileTask::continueWithFailedFile(bool retry, const QString& link)
+{
+ // retry=false mean skip the current file and continue with the
+ // next one. It is only used in PostFilesTask which contains a
+ // list of files to be uploaded.
+ assert(retry);
+ start();
+}
+
+void ReliablePostFileTask::onPostFileTaskFinished(bool result)
+{
+ // First check if we should retry on failure
+ if (!result) {
+ if (task_->error() == FileNetworkTask::ApiRequestError && maybeRetry()) {
+ return;
+ }
+ }
+
+ http_error_code_ = task_->httpErrorCode();
+ error_string_ = task_->errorString();
+ error_ = task_->error();
+
+ if (!useResumableUpload()) {
+ // Simple upload
+ if (result) {
+ emit finished(true);
+ } else {
+ handlePostFileTaskFailure();
+ }
+ return;
+ }
+
+ // printf ("total_size: %llu, offset: %llu, chunk: %u\n", total_size_, current_offset_, current_chunk_size_);
+
+ // Resumable upload
+ if (!result) {
+ handlePostFileTaskFailure();
+ return;
+ }
+
+ // A chunk is successfully uploaded to the server
+ if (current_offset_ + current_chunk_size_ >= total_size_) {
+ emit finished(true);
+ return;
+ } else {
+ current_offset_ += current_chunk_size_;
+ // Continue with next chunk
+ startPostFileTask();
+ }
+}
+
+void ReliablePostFileTask::onPostFileTaskProgressUpdate(qint64 done, qint64 total)
+{
+ done_ = current_offset_ + done;
+ emit progressUpdate(done_, total_size_);
+}
+
+const QString& ReliablePostFileTask::oid() const
+{
+ return task_->oid();
+}
+
+void ReliablePostFileTask::cancel()
+{
+ // Must cancel itself first to set the canceled_ flag to avoid it being
+ // retried
+ FileServerTask::cancel();
+ if (task_) {
+ QMetaObject::invokeMethod(task_.data(), "cancel");
+ }
+}
+
+void ReliablePostFileTask::onHttpRequestFinished()
+{
+ // Nothing to do. The actual POST http request is managed by PostFileTask
+}
+
+PostFileTask::PostFileTask(const QUrl& url,
+ const QString& parent_dir,
+ const QString& local_path,
+ QFile *file,
+ const QString& name,
+ const bool use_upload,
+ quint64 total_size,
+ quint64 start_offset,
+ quint32 chunk_size,
+ const bool need_idx_progress)
+ : FileServerTask(url, local_path),
+ parent_dir_(parent_dir),
+ file_(file),
+ name_(name),
+ use_upload_(use_upload),
+ total_size_(total_size),
+ start_offset_(start_offset),
+ chunk_size_(chunk_size),
+ need_idx_progress_(need_idx_progress)
+{
+}
+
+PostFileTask::PostFileTask(const QUrl& url,
+ const QString& parent_dir,
+ const QString& local_path,
+ QFile *file,
+ const QString& name,
+ const QString& relative_path,
+ quint64 total_size)
+ : FileServerTask(url, local_path),
+ parent_dir_(parent_dir),
+ file_(file),
+ name_(name),
+ use_upload_(true),
+ relative_path_(relative_path),
+ total_size_(total_size),
+ start_offset_(0),
+ chunk_size_(-1),
+ need_idx_progress_(false)
+{
+}
+
+PostFileTask::~PostFileTask()
+{
+}
+
+void PostFileTask::prepare()
+{
+ // printThread("post file task is in thread");
+}
+
+bool PostFileTask::isChunked() const
+{
+ return chunk_size_ > 0;
+}
+
+/**
+ * This member function may be called in two places:
+ * 1. when task is first started
+ * 2. when the request is redirected
+ */
+void PostFileTask::sendRequest()
+{
+ QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType, this);
+ // parent_dir param
+ QHttpPart parentdir_part, file_part;
+ if (use_upload_) {
+ parentdir_part.setHeader(QNetworkRequest::ContentDispositionHeader,
+ kParentDirParam);
+ parentdir_part.setBody(parent_dir_.toUtf8());
+ } else {
+ parentdir_part.setHeader(QNetworkRequest::ContentDispositionHeader,
+ kTargetFileParam);
+ parentdir_part.setBody(::pathJoin(parent_dir_, name_).toUtf8());
+ }
+ multipart->append(parentdir_part);
+
+ // "relative_path" param
+ if (!relative_path_.isEmpty()) {
+ QHttpPart part;
+ part.setHeader(QNetworkRequest::ContentDispositionHeader,
+ kRelativePathParam);
+ part.setBody(relative_path_.toUtf8());
+ multipart->append(part);
+ }
+
+ // "file" param
+ file_part.setHeader(QNetworkRequest::ContentDispositionHeader,
+ QString(kFileParamTemplate).arg(name_).toUtf8());
+ file_part.setHeader(QNetworkRequest::ContentTypeHeader,
+ kContentTypeApplicationOctetStream);
+
+ if (isChunked()) {
+ // MMap the chunk to read the chunk content from the file
+ uchar *buf = file_->map(start_offset_, chunk_size_);
+ if (!buf) {
+ setError(FileNetworkTask::FileIOError, "Failed to read file content");
+ emit finished(false);
+ return;
+ }
+ QBuffer *buffer = new QBuffer();
+ buffer->setParent(this);
+ // This would copy the mmaped file content to the QBuffer right now
+ buffer->setData(QByteArray(reinterpret_cast<const char*>(buf), chunk_size_));
+ buffer->open(QIODevice::ReadOnly);
+ file_->unmap(buf);
+ file_part.setBodyDevice(buffer);
+ } else {
+ file_part.setBodyDevice(file_);
+ }
+ multipart->append(file_part);
+
+ // "need_idx_progress" param
+ if (need_idx_progress_) {
+ url_ = ::includeQueryParams(url_, {{"need_idx_progress", "true"}});
+ }
+
+ QNetworkRequest request(url_);
+ request.setRawHeader("Content-Type",
+ "multipart/form-data; boundary=" + multipart->boundary());
+ if (isChunked()) {
+ setContentRangeHeader(&request);
+ }
+
+ reply_ = getQNAM()->post(request, multipart);
+
+ connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+ this, SLOT(onSslErrors(const QList<QSslError>&)));
+ connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+ connect(reply_, SIGNAL(uploadProgress(qint64,qint64)),
+ this, SIGNAL(progressUpdate(qint64, qint64)));
+}
+
+void PostFileTask::setContentRangeHeader(QNetworkRequest *request)
+{
+ auto range_header = QString("bytes %1-%2/%3")
+ .arg(QString::number(start_offset_),
+ QString::number(start_offset_ + chunk_size_ - 1),
+ QString::number(file_->size()));
+ // printf("range_header = %s\n", range_header.toUtf8().data());
+ request->setRawHeader("Content-Range", range_header.toUtf8());
+ request->setRawHeader("Content-Disposition",
+ QString(kFileNameHeaderTemplate).arg(name_).toUtf8());
+}
+
+void PostFileTask::onHttpRequestFinished()
+{
+ if (canceled_) {
+ return;
+ }
+
+ if (handleHttpRedirect()) {
+ return;
+ }
+
+ oid_ = reply_->readAll();
+
+ emit finished(true);
+}
--- /dev/null
+#ifndef SEAFILE_CLIETN_FILEBROWSER_RELIABLE_TAKS_H
+#define SEAFILE_CLIETN_FILEBROWSER_RELIABLE_TAKS_H
+
+#include "tasks.h"
+
+class PostFileTask;
+class ApiError;
+class QBuffer;
+
+// A wrapper of the PostFileTask class to upload a single file. It adds extra
+// features like:
+// 1. retrying
+// 2. chunked uploads: send big files in 1MB chunks, and each chunk is sent with a PostFileTask
+// 3. aggregate and show correct progress when retring and chunked uploads
+//
+// This makes PostFileTask very simple - it only need to focus on uploading a
+// single piece of a file, with all uppler level features like retrying and
+// chunking implemented here.
+class ReliablePostFileTask : public FileServerTask {
+ Q_OBJECT
+public:
+ // Instance created using this constructor would use chunked uploads (if
+ // the server supports it).
+ ReliablePostFileTask(const Account &account,
+ const QString &repo_id,
+ const QUrl &url,
+ const QString &parent_dir,
+ const QString &local_path,
+ const QString &name,
+ const bool use_upload,
+ const bool accept_user_confirmation);
+
+ // Instance created using this constructor *would not* use chunked uploads.
+ // This is used for uploading files in folder uploads.
+ ReliablePostFileTask(const QUrl &url,
+ const QString &parent_dir,
+ const QString &local_path,
+ const QString &name,
+ const QString &relative_path);
+
+ ~ReliablePostFileTask();
+
+ virtual const QString &oid() const;
+ virtual void continueWithFailedFile(bool retry, const QString& link);
+
+public slots:
+ void cancel();
+
+protected:
+ bool retryEnabled();
+ void prepare();
+ void sendRequest();
+ void onHttpRequestFinished();
+ void checkUploadedBytes();
+
+private slots:
+ void onGetFileUploadedBytesSuccess(bool support_chunked_uploading, quint64 uploaded_bytes);
+ void onGetFileUploadedBytesFailed(const ApiError& error);
+ void onPostFileTaskFinished(bool result);
+ void onPostFileTaskProgressUpdate(qint64 done, qint64 total);
+
+private:
+ void setContentRangeHeader(QNetworkRequest *request);
+ void setupSignals();
+ void createPostFileTask();
+ void startPostFileTask();
+ bool useResumableUpload() const;
+ void handlePostFileTaskFailure();
+
+ const Account account_;
+ const QString repo_id_;
+ const bool part_of_folder_upload_;
+
+ const QString parent_dir_;
+ QFile *file_;
+ const QString name_;
+ const bool use_upload_;
+ const QString relative_path_;
+
+ quint64 done_;
+ quint64 total_size_;
+
+ //---------------------------------
+ // Used for resumable (chunk) uploads
+ //---------------------------------
+ bool resumable_;
+ quint64 current_offset_;
+ quint32 current_chunk_size_;
+ bool need_idx_progress_;
+
+ // The underlying task that sends the POST file request
+ QScopedPointer<PostFileTask, doDeleteLater<PostFileTask> > task_;
+ QScopedPointer<GetFileUploadedBytesRequest, doDeleteLater<GetFileUploadedBytesRequest> > file_uploaded_bytes_req_;
+
+ bool accept_user_confirmation_;
+};
+
+class PostFileTask : public FileServerTask {
+ Q_OBJECT
+ friend class ReliablePostFileTask;
+public:
+ PostFileTask(const QUrl& url,
+ const QString& parent_dir,
+ const QString& local_path,
+ QFile *file,
+ const QString& name,
+ const bool use_upload,
+ quint64 total_size,
+ quint64 start_offset,
+ quint32 chunk_size,
+ const bool need_idx_progress);
+
+ PostFileTask(const QUrl& url,
+ const QString& parent_dir,
+ const QString& local_path,
+ QFile *file,
+ const QString& name,
+ const QString& relative_path,
+ quint64 total_size);
+ ~PostFileTask();
+
+protected:
+ void prepare();
+ void sendRequest();
+ void onHttpRequestFinished();
+
+private:
+ bool isChunked() const;
+ void setContentRangeHeader(QNetworkRequest *request);
+
+ const QString parent_dir_;
+ QFile *file_;
+ const QString name_;
+ const bool use_upload_;
+ const QString relative_path_;
+
+ quint64 total_size_;
+
+ quint64 start_offset_;
+ qint32 chunk_size_;
+ bool need_idx_progress_;
+};
+
+#endif // SEAFILE_CLIETN_FILEBROWSER_TAKS_H
--- /dev/null
+#include <jansson.h>
+#include <QDateTime>
+
+#include "utils/json-utils.h"
+
+#include "seaf-dirent.h"
+
+namespace {
+
+void initCommonFields(SeafDirent *dirent) {
+ dirent->mtime = QDateTime::currentDateTime().toTime_t();
+ dirent->readonly = false;
+ dirent->is_locked = false;
+ dirent->locked_by_me = false;
+}
+
+}
+
+SeafDirent SeafDirent::fromJSON(const json_t *root, json_error_t */* error */)
+{
+ SeafDirent dirent;
+ Json json(root);
+
+ dirent.id = json.getString("id");
+ dirent.name = json.getString("name");
+
+ QString type = json.getString("type");
+ if (type == "file") {
+ dirent.type = FILE;
+ dirent.size = json.getLong("size");
+ } else {
+ dirent.type = DIR;
+ }
+ dirent.readonly = json.getString("permission") == "r" ? true : false;
+ dirent.mtime = json.getLong("mtime");
+
+ dirent.is_locked = json.getBool("is_locked");
+ dirent.lock_owner = json.getString("lock_owner");
+ dirent.lock_owner_name = json.getString("lock_owner_name");
+ dirent.lock_time = json.getLong("lock_time");
+ dirent.locked_by_me = json.getBool("locked_by_me");
+ dirent.modifier_name = json.getString("modifier_name");
+
+ return dirent;
+}
+
+QList<SeafDirent> SeafDirent::listFromJSON(const json_t *json, json_error_t *error)
+{
+ QList<SeafDirent> dirents;
+ for (size_t i = 0; i < json_array_size(json); i++) {
+ SeafDirent dirent = fromJSON(json_array_get(json, i), error);
+ dirents.push_back(dirent);
+ }
+
+ return dirents;
+}
+
+const QString& SeafDirent::getLockOwnerDisplayString() const
+{
+ return !lock_owner_name.isEmpty() ? lock_owner_name : lock_owner;
+}
+
+SeafDirent SeafDirent::dir(const QString& name)
+{
+ SeafDirent dirent;
+ dirent.type = DIR;
+ dirent.name = name;
+
+ initCommonFields(&dirent);
+ return dirent;
+}
+
+SeafDirent SeafDirent::file(const QString& name, quint64 size)
+{
+ SeafDirent dirent;
+ dirent.type = FILE;
+ dirent.name = name;
+ dirent.size = size;
+
+ initCommonFields(&dirent);
+ return dirent;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_API_SEAF_DIRENT_H
+#define SEAFILE_CLIENT_API_SEAF_DIRENT_H
+
+#include <jansson.h>
+
+#include <vector>
+#include <QString>
+#include <QList>
+#include <QMetaType>
+
+class SeafDirent {
+public:
+ enum Type {
+ DIR,
+ FILE
+ };
+
+ Type type;
+ bool readonly;
+ QString id;
+ QString name;
+ quint64 size;
+ quint64 mtime;
+
+ bool is_locked;
+ bool locked_by_me;
+ QString lock_owner;
+ QString lock_owner_name;
+ quint64 lock_time;
+ QString modifier_name;
+
+ bool isDir() const { return type == DIR; }
+ bool isFile() const { return type == FILE; }
+
+ const QString& getLockOwnerDisplayString() const;
+
+ static SeafDirent fromJSON(const json_t*, json_error_t *error);
+ static QList<SeafDirent> listFromJSON(const json_t*, json_error_t *error);
+
+ static SeafDirent dir(const QString& name);
+ static SeafDirent file(const QString& name, quint64 size);
+};
+
+
+/**
+ * Register with QMetaType so we can wrap it with QVariant::fromValue
+ */
+Q_DECLARE_METATYPE(SeafDirent)
+
+#endif // SEAFILE_CLIENT_API_SEAF_DIRENT_H
+
--- /dev/null
+#include "seafilelink-dialog.h"
+
+#include <QtGlobal>
+#include <QtWidgets>
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "open-local-helper.h"
+
+SeafileLinkDialog::SeafileLinkDialog(const QString& smart_link, const QString& protocol_link, QWidget *parent)
+ :web_link_(smart_link), protocol_link_(protocol_link)
+{
+ setWindowTitle(tr("%1 Internal Link").arg(getBrand()));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setSpacing(5);
+ layout->setContentsMargins(9, 9, 9, 9);
+
+ QString copy_to_str = tr("Copy to clipboard");
+ QIcon copy_to_icon = awesome->icon(icon_copy);
+
+ //
+ // create web link related
+ //
+ QLabel *web_label = new QLabel(tr("%1 Internal Link:").arg(getBrand()));
+ layout->addWidget(web_label);
+ QHBoxLayout *web_layout = new QHBoxLayout;
+
+ web_editor_ = new QLineEdit;
+ web_editor_->setText(web_link_);
+ web_editor_->selectAll();
+ web_editor_->setReadOnly(true);
+ web_editor_->setCursorPosition(0);
+
+ web_layout->addWidget(web_editor_);
+
+ QPushButton *web_copy_to = new QPushButton;
+ web_copy_to->setIcon(copy_to_icon);
+ web_copy_to->setToolTip(copy_to_str);
+ web_layout->addWidget(web_copy_to);
+ connect(web_copy_to, SIGNAL(clicked()), this, SLOT(onCopyWebText()));
+ layout->addLayout(web_layout);
+
+ //
+ // create seafile-protocol link related
+ //
+ QLabel *protocol_label = new QLabel(tr("%1 Desktop Access Link:").arg(getBrand()));
+ layout->addWidget(protocol_label);
+ QHBoxLayout *protocol_layout = new QHBoxLayout;
+
+ protocol_editor_ = new QLineEdit;
+ protocol_editor_->setText(protocol_link_);
+ protocol_editor_->selectAll();
+ protocol_editor_->setReadOnly(true);
+ protocol_editor_->setCursorPosition(0);
+
+ protocol_layout->addWidget(protocol_editor_);
+
+ QPushButton *protocol_copy_to = new QPushButton;
+ protocol_copy_to->setIcon(copy_to_icon);
+ protocol_copy_to->setToolTip(copy_to_str);
+ protocol_layout->addWidget(protocol_copy_to);
+ connect(protocol_copy_to, SIGNAL(clicked()), this, SLOT(onCopyProtocolText()));
+ layout->addLayout(protocol_layout);
+
+ QHBoxLayout *hlayout = new QHBoxLayout;
+
+ QWidget *spacer = new QWidget;
+ spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+ hlayout->addWidget(spacer);
+
+ QWidget *spacer2 = new QWidget;
+ spacer2->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+ hlayout->addWidget(spacer2);
+
+ QWidget *spacer3 = new QWidget;
+ spacer3->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+ hlayout->addWidget(spacer3);
+
+ QPushButton *ok = new QPushButton(tr("OK"));
+ hlayout->addWidget(ok);
+ connect(ok, SIGNAL(clicked()), this, SLOT(accept()));
+ ok->setFocus();
+
+ layout->addLayout(hlayout);
+
+ setLayout(layout);
+
+ setMinimumWidth(450);
+}
+
+void SeafileLinkDialog::onCopyWebText()
+{
+// for mac, qt copys many minedatas beside public.utf8-plain-text
+// e.g. public.vcard, which we don't want to use
+#ifndef Q_OS_MAC
+ QApplication::clipboard()->setText(web_link_);
+#else
+ utils::mac::copyTextToPasteboard(web_link_);
+#endif
+}
+
+void SeafileLinkDialog::onCopyProtocolText()
+{
+// for mac, qt copys many minedatas beside public.utf8-plain-text
+// e.g. public.vcard, which we don't want to use
+#ifndef Q_OS_MAC
+ QApplication::clipboard()->setText(protocol_link_);
+#else
+ utils::mac::copyTextToPasteboard(protocol_link_);
+#endif
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_SEAFILELINK_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_SEAFILELINK_DIALOG_H
+#include <QDialog>
+
+class QLineEdit;
+class Account;
+class SeafileLinkDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ SeafileLinkDialog(const QString& smart_link, const QString& protocol_link, QWidget *parent);
+
+private slots:
+ void onCopyWebText();
+ void onCopyProtocolText();
+
+private:
+ QString web_link_;
+ const QString protocol_link_;
+ QLineEdit *web_editor_;
+ QLineEdit *protocol_editor_;
+};
+
+#endif
--- /dev/null
+#include "sharedlink-dialog.h"
+
+#include <QtGlobal>
+#include <QtWidgets>
+#include "utils/utils-mac.h"
+
+SharedLinkDialog::SharedLinkDialog(const QString &text, QWidget *parent, bool is_shared_link)
+ : text_(text)
+{
+ if (is_shared_link) {
+ setWindowTitle(tr("Share Link"));
+ } else {
+ setWindowTitle(tr("Upload Link"));
+ }
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ QVBoxLayout *layout = new QVBoxLayout;
+
+ QLabel *label;
+ if (is_shared_link) {
+ label = new QLabel(tr("Share link:"));
+ } else {
+ label = new QLabel(tr("Upload link:"));
+ }
+ layout->addWidget(label);
+ layout->setSpacing(5);
+ layout->setContentsMargins(9, 9, 9, 9);
+
+ editor_ = new QLineEdit;
+ editor_->setText(text_);
+ editor_->selectAll();
+ editor_->setReadOnly(true);
+ layout->addWidget(editor_);
+
+ QHBoxLayout *hlayout = new QHBoxLayout;
+
+ QCheckBox *is_download_checked = new QCheckBox(tr("Direct Download"));
+ if (!is_shared_link) {
+ is_download_checked->hide();
+ }
+ connect(is_download_checked, SIGNAL(stateChanged(int)),
+ this, SLOT(onDownloadStateChanged(int)));
+ hlayout->addWidget(is_download_checked);
+
+ QWidget *spacer = new QWidget;
+ spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+ hlayout->addWidget(spacer);
+
+ QWidget *spacer2 = new QWidget;
+ spacer2->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+ hlayout->addWidget(spacer2);
+
+ QPushButton *copy_to = new QPushButton(tr("Copy to clipboard"));
+ hlayout->addWidget(copy_to);
+ connect(copy_to, SIGNAL(clicked()), this, SLOT(onCopyText()));
+
+ QPushButton *ok = new QPushButton(tr("OK"));
+ hlayout->addWidget(ok);
+ connect(ok, SIGNAL(clicked()), this, SLOT(accept()));
+
+ layout->addLayout(hlayout);
+
+ setLayout(layout);
+
+ setMinimumWidth(300);
+ setMaximumWidth(400);
+}
+
+void SharedLinkDialog::onCopyText()
+{
+// for mac, qt copys many minedatas beside public.utf8-plain-text
+// e.g. public.vcard, which we don't want to use
+#ifndef Q_OS_MAC
+ QApplication::clipboard()->setText(editor_->text());
+#else
+ utils::mac::copyTextToPasteboard(editor_->text());
+#endif
+}
+
+void SharedLinkDialog::onDownloadStateChanged(int state)
+{
+ if (state == Qt::Checked)
+ editor_->setText(text_ + "?dl=1");
+ else
+ editor_->setText(text_);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_SHAREDLINK_DIALOG_H
+#define SEAFILE_CLIENT_FILE_BROWSER_SHAREDLINK_DIALOG_H
+#include <QDialog>
+
+class QLineEdit;
+class SharedLinkDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ SharedLinkDialog(const QString &text, QWidget *parent, bool is_shared_link = true);
+
+private slots:
+ void onCopyText();
+ void onDownloadStateChanged(int state);
+private:
+ const QString text_;
+ QLineEdit *editor_;
+};
+
+#endif
--- /dev/null
+#include <QThread>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QHttpMultiPart>
+#include <QHttpPart>
+#include <QFile>
+#include <QFileInfo>
+#include <QTemporaryFile>
+#include <QSslError>
+#include <QSslConfiguration>
+#include <QSslCertificate>
+#include <QDirIterator>
+#include <QTimer>
+#include <QApplication>
+#include <QMutexLocker>
+#include <QNetworkConfigurationManager>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "certs-mgr.h"
+#include "api/api-error.h"
+#include "configurator.h"
+#include "network-mgr.h"
+#include "reliable-upload.h"
+#include "tasks.h"
+
+namespace {
+
+const char *kFileDownloadTmpDirName = "fcachetmp";
+
+const int kMaxRedirects = 3;
+const int kFileServerTaskMaxRetry = 3;
+const int kFileServerTaskRetryIntervalSecs = 10;
+
+class QNAMWrapper {
+public:
+ QNAMWrapper() {
+ should_reset_qnam_ = false;
+ network_mgr_ = nullptr;
+ }
+
+ QNetworkAccessManager *getQNAM() {
+ QMutexLocker lock(&network_mgr_lock_);
+
+ if (!network_mgr_) {
+ network_mgr_ = createQNAM();
+ } else if (should_reset_qnam_) {
+ network_mgr_->deleteLater();
+ network_mgr_ = createQNAM();
+ should_reset_qnam_ = false;
+ }
+ return network_mgr_;
+ }
+
+ QNetworkAccessManager *createQNAM() {
+ QNetworkAccessManager *manager = new QNetworkAccessManager;
+ NetworkManager::instance()->addWatch(manager);
+ manager->setConfiguration(
+ QNetworkConfigurationManager().defaultConfiguration());
+ return manager;
+ }
+
+ void resetQNAM() {
+ QMutexLocker lock(&network_mgr_lock_);
+ should_reset_qnam_ = true;
+ }
+
+private:
+ QNetworkAccessManager* network_mgr_;
+ QMutex network_mgr_lock_;
+ bool should_reset_qnam_;
+};
+
+QNAMWrapper* qnam_wrapper_ = new QNAMWrapper();
+
+} // namesapce
+
+QThread* FileNetworkTask::worker_thread_;
+
+FileNetworkTask::FileNetworkTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path)
+ : account_(account),
+ repo_id_(repo_id),
+ path_(path),
+ local_path_(local_path),
+ canceled_(false),
+ progress_(0, 0)
+{
+ fileserver_task_ = NULL;
+ get_link_req_ = NULL;
+ http_error_code_ = 0;
+ auto_delete_ = true;
+}
+
+FileNetworkTask::~FileNetworkTask()
+{
+ // printf ("destructor called for FileNetworkTask\n");
+ if (get_link_req_) {
+ get_link_req_->deleteLater();
+ get_link_req_ = nullptr;
+ }
+ if (fileserver_task_) {
+ fileserver_task_->deleteLater();
+ fileserver_task_ = nullptr;
+ }
+}
+
+QString FileNetworkTask::fileName() const
+{
+ return QFileInfo(path_).fileName();
+}
+
+void FileNetworkTask::start()
+{
+ createGetLinkRequest();
+ connect(get_link_req_, SIGNAL(success(const QString&)),
+ this, SLOT(onLinkGet(const QString&)));
+ connect(get_link_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetLinkFailed(const ApiError&)));
+ get_link_req_->send();
+}
+
+void FileNetworkTask::onFileServerTaskProgressUpdate(qint64 transferred, qint64 total)
+{
+ progress_.transferred = transferred;
+ progress_.total = total;
+ emit progressUpdate(transferred, total);
+}
+
+void FileNetworkTask::onFileServerTaskNameUpdate(QString current_name)
+{
+ emit nameUpdate(current_name);
+}
+
+void FileNetworkTask::onLinkGet(const QString& link)
+{
+ startFileServerTask(link);
+}
+
+void FileNetworkTask::startFileServerTask(const QString& link)
+{
+ createFileServerTask(link);
+
+ connect(fileserver_task_, SIGNAL(progressUpdate(qint64, qint64)),
+ this, SLOT(onFileServerTaskProgressUpdate(qint64, qint64)));
+ connect(fileserver_task_, SIGNAL(nameUpdate(QString)),
+ this, SLOT(onFileServerTaskNameUpdate(QString)));
+ connect(fileserver_task_, SIGNAL(finished(bool)),
+ this, SLOT(onFileServerTaskFinished(bool)));
+ connect(fileserver_task_, SIGNAL(retried(int)),
+ this, SIGNAL(retried(int)));
+
+ if (!worker_thread_) {
+ worker_thread_ = new QThread;
+ worker_thread_->start();
+ }
+
+ if (type() == Download) {
+ // From now on the this task would run in the worker thread
+ fileserver_task_->moveToThread(worker_thread_);
+ QMetaObject::invokeMethod(fileserver_task_, "start");
+ } else {
+ // ReliablePostFileTask is a bit complicated and it would manage the
+ // thread-affinity itself.
+ fileserver_task_->start();
+ }
+}
+
+void FileNetworkTask::cancel()
+{
+ canceled_ = true;
+ if (get_link_req_) {
+ get_link_req_->deleteLater();
+ get_link_req_ = 0;
+ }
+ if (fileserver_task_) {
+ QMetaObject::invokeMethod(fileserver_task_, "cancel");
+ }
+ error_ = TaskCanceled;
+ error_string_ = tr("Operation canceled");
+ onFinished(false);
+}
+
+void FileNetworkTask::onFileServerTaskFinished(bool success)
+{
+ if (canceled_) {
+ return;
+ }
+ if (!fileserver_task_->canceled() && !success) {
+ error_ = fileserver_task_->error();
+ error_string_ = fileserver_task_->errorString();
+ http_error_code_ = fileserver_task_->httpErrorCode();
+ failed_path_ = fileserver_task_->failedPath();
+ }
+ oid_ = fileserver_task_->oid();
+ url_ = fileserver_task_->url();
+ onFinished(success);
+}
+
+void FileNetworkTask::onFinished(bool success)
+{
+ emit finished(success);
+ if (auto_delete_) {
+ deleteLater();
+ }
+}
+
+void FileNetworkTask::onGetLinkFailed(const ApiError& error)
+{
+ error_ = ApiRequestError;
+ error_string_ = error.toString();
+ if (error.type() == ApiError::HTTP_ERROR) {
+ http_error_code_ = error.httpErrorCode();
+ }
+ onFinished(false);
+}
+
+FileNetworkTask::Progress::Progress(qint64 transferred, qint64 total)
+{
+ this->transferred = transferred;
+ this->total = total;
+}
+
+QString FileNetworkTask::Progress::toString() const
+{
+ if (total > 0) {
+ return QString::number(100 * transferred / total) + "%";
+ }
+ return tr("pending");
+}
+
+FileDownloadTask::FileDownloadTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ bool is_save_as_task)
+ : FileNetworkTask(account, repo_id, path, local_path), is_save_as_task_(is_save_as_task)
+{
+}
+
+void FileDownloadTask::createGetLinkRequest()
+{
+ if (get_link_req_) {
+ get_link_req_->deleteLater();
+ }
+ get_link_req_ = new GetFileDownloadLinkRequest(account_, repo_id_, path_);
+}
+
+void FileDownloadTask::onLinkGet(const QString& link)
+{
+ GetFileDownloadLinkRequest *req = (GetFileDownloadLinkRequest *)get_link_req_;
+ file_id_ = req->fileId();
+ FileNetworkTask::onLinkGet(link);
+}
+
+void FileDownloadTask::createFileServerTask(const QString& link)
+{
+ fileserver_task_ = new GetFileTask(link, local_path_);
+}
+
+FileUploadTask::FileUploadTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ const QString& name,
+ const bool use_upload,
+ const bool accept_user_confirmation)
+ : FileNetworkTask(account, repo_id, path, local_path),
+ name_(name),
+ use_upload_(use_upload),
+ accept_user_confirmation_(accept_user_confirmation)
+{
+}
+
+FileUploadTask::FileUploadTask(const FileUploadTask& rhs)
+ : FileNetworkTask(rhs.account_, rhs.repo_id_, rhs.path_, rhs.local_path_),
+ name_(rhs.name_),
+ use_upload_(rhs.use_upload_),
+ accept_user_confirmation_(rhs.accept_user_confirmation_)
+{
+}
+
+void FileUploadTask::createGetLinkRequest()
+{
+ get_link_req_ = new GetFileUploadLinkRequest(account_, repo_id_, path_, use_upload_);
+}
+
+void FileUploadTask::createFileServerTask(const QString& link)
+{
+ fileserver_task_ = new ReliablePostFileTask(account_, repo_id_, link, path_, local_path_,
+ name_, use_upload_, accept_user_confirmation_);
+}
+
+void FileUploadTask::startFileServerTask(const QString& link)
+{
+ FileNetworkTask::startFileServerTask(link);
+ connect(fileserver_task_, SIGNAL(oneFileFailed(const QString&, bool)),
+ this, SLOT(onOneFileFailed(const QString&, bool)));
+}
+
+void FileUploadTask::onOneFileFailed(const QString& filename, bool single_file)
+{
+ emit oneFileFailed(filename, single_file);
+}
+
+void FileUploadTask::continueWithFailedFile(bool retry)
+{
+ retry_ = retry;
+ createGetLinkRequest();
+ connect(get_link_req_, SIGNAL(success(const QString&)),
+ this, SLOT(onLinkGetAgain(const QString&)));
+ connect(get_link_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetLinkFailed(const ApiError&)));
+ get_link_req_->send();
+}
+
+void FileUploadTask::onLinkGetAgain(const QString& link)
+{
+ fileserver_task_->continueWithFailedFile(retry_, link);
+}
+
+FileUploadMultipleTask::FileUploadMultipleTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ const QStringList& names,
+ bool use_upload)
+ : FileUploadTask(account, repo_id, path, local_path, QString(), use_upload),
+ names_(names)
+{
+}
+
+void FileUploadMultipleTask::createFileServerTask(const QString& link)
+{
+ fileserver_task_ = new PostFilesTask(link, path_, local_path_, names_, false);
+}
+
+const QStringList& FileUploadMultipleTask::successfulNames()
+{
+ return ((PostFilesTask *)fileserver_task_)->successfulNames();
+}
+
+
+FileUploadDirectoryTask::FileUploadDirectoryTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ const QString& name)
+ : FileUploadTask(account, repo_id, path, local_path, name)
+{
+}
+
+void FileUploadDirectoryTask::createFileServerTask(const QString& link)
+{
+ QStringList names;
+
+ if (local_path_ == "/")
+ qWarning("attempt to upload the root directory, you should avoid it\n");
+ QDir dir(local_path_);
+
+ QDirIterator iterator(dir.absolutePath(), QDirIterator::Subdirectories);
+ // XXX (lins05): Move these operations into a thread
+ while (iterator.hasNext()) {
+ iterator.next();
+ QString file_path = iterator.filePath();
+ QString relative_path = dir.relativeFilePath(file_path);
+ QString base_name = ::getBaseName(file_path);
+ if (base_name == "." || base_name == "..") {
+ continue;
+ }
+ if (!iterator.fileInfo().isDir()) {
+ names.push_back(relative_path);
+ } else {
+ if (account_.isAtLeastVersion(4, 4, 0)) {
+ // printf("a folder: %s\n", file_path.toUtf8().data());
+ if (QDir(file_path).entryList().length() == 2) {
+ // only contains . and .., so an empty folder
+ // printf("an empty folder: %s\n", file_path.toUtf8().data());
+ empty_subfolders_.append(::pathJoin(::getBaseName(local_path_), relative_path));
+ }
+ }
+ }
+ }
+
+ if (names.isEmpty() && empty_subfolders_.isEmpty()) {
+ // The folder dragged into cloud file browser is an empty one. We use
+ // the special name "." to represent it.
+ empty_subfolders_.append(".");
+ }
+
+ // printf("total empty folders: %d for %s\n", empty_subfolders_.length(), dir.absolutePath().toUtf8().data());
+ fileserver_task_ = new PostFilesTask(link, path_, dir.absolutePath(), names, true);
+}
+
+void FileUploadDirectoryTask::onFinished(bool success)
+{
+ if (!success || (empty_subfolders_.empty())) {
+ FileUploadTask::onFinished(success);
+ return;
+ }
+
+ nextEmptyFolder();
+}
+
+void FileUploadDirectoryTask::nextEmptyFolder()
+{
+ if (empty_subfolders_.isEmpty()) {
+ FileUploadDirectoryTask::onFinished(true);
+ return;
+ }
+
+ QString folder = empty_subfolders_.takeFirst();
+
+ bool create_parents = true;
+ if (folder == ".") {
+ // This is the case of an empty top-level folder.
+ create_parents = false;
+ folder = ::getBaseName(local_path_);
+ }
+
+ create_dir_req_.reset(new CreateDirectoryRequest(
+ account_, repo_id_, ::pathJoin(path_, folder), create_parents));
+
+ connect(create_dir_req_.data(), SIGNAL(success(const QString&)),
+ this, SLOT(nextEmptyFolder()));
+ connect(create_dir_req_.data(), SIGNAL(failed(const ApiError&)),
+ this, SLOT(onCreateDirFailed(const ApiError&)));
+ create_dir_req_->send();
+}
+
+void FileUploadDirectoryTask::onCreateDirFailed(const ApiError &error)
+{
+ error_ = ApiRequestError;
+ error_string_ = error.toString();
+ http_error_code_ = error.httpErrorCode();
+ FileUploadDirectoryTask::onFinished(false);
+}
+
+FileServerTask::FileServerTask(const QUrl& url, const QString& local_path)
+ : url_(url),
+ local_path_(local_path),
+ reply_(nullptr),
+ canceled_(false),
+ redirect_count_(0),
+ retry_count_(0),
+ http_error_code_(0)
+{
+}
+
+FileServerTask::~FileServerTask()
+{
+}
+
+void FileServerTask::resetQNAM()
+{
+ qnam_wrapper_->resetQNAM();
+}
+
+QNetworkAccessManager *FileServerTask::getQNAM()
+{
+ QNetworkAccessManager *qnam = qnam_wrapper_->getQNAM();
+ connect(qnam, SIGNAL(destroyed(QObject *)), this, SLOT(doAbort()));
+ return qnam;
+}
+
+void FileServerTask::doAbort()
+{
+ if (reply_ && reply_->isRunning()) {
+ qWarning("aborting FileServerTask %s on network error", toCStr(reply_->url().toString()));
+ reply_->abort();
+ }
+}
+
+void FileServerTask::onSslErrors(const QList<QSslError>& errors)
+{
+ if (canceled_) {
+ return;
+ }
+ QUrl url = reply_->url();
+ QSslCertificate cert = reply_->sslConfiguration().peerCertificate();
+ CertsManager *mgr = seafApplet->certsManager();
+ if (!cert.isNull() && cert == mgr->getCertificate(url.toString())) {
+ reply_->ignoreSslErrors();
+ return;
+ }
+}
+
+void FileServerTask::start()
+{
+ prepare();
+ sendRequest();
+}
+
+void FileServerTask::cancel()
+{
+ canceled_ = true;
+ if (reply_) {
+ reply_->abort();
+ }
+}
+
+bool FileServerTask::retryEnabled()
+{
+ return false;
+}
+
+void FileServerTask::retry()
+{
+ if (canceled_) {
+ qWarning("[file server task] stop retrying because task is cancelled\n");
+ return;
+ }
+ qDebug("[file server task] now retry the file server task for the %d time\n", retry_count_);
+ emit retried(retry_count_);
+ start();
+}
+
+bool FileServerTask::maybeRetry()
+{
+ if (canceled_ || !retryEnabled()) {
+ return false;
+ }
+ if (retry_count_ >= kFileServerTaskMaxRetry) {
+ return false;
+ } else {
+ retry_count_++;
+ qDebug("[file server task] schedule file server task retry for the %d time\n", retry_count_);
+ QTimer::singleShot(kFileServerTaskRetryIntervalSecs * 1000, this, SLOT(retry()));
+ return true;
+ }
+}
+
+void FileServerTask::httpRequestFinished()
+{
+ if (canceled_) {
+ setError(FileNetworkTask::TaskCanceled, tr("task cancelled"));
+ emit finished(false);
+ return;
+ }
+
+ int code = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+ if (code == 0 && reply_->error() != QNetworkReply::NoError) {
+
+ NetworkStatusDetector::instance()->setNetworkFailure(reply_->error());
+
+ qWarning("[file server task] network error: %s\n", toCStr(reply_->errorString()));
+ if (!maybeRetry()) {
+ setError(FileNetworkTask::ApiRequestError, reply_->errorString());
+ emit finished(false);
+ return;
+ }
+ return;
+ }
+
+ if (handleHttpRedirect()) {
+ return;
+ }
+
+ if ((code / 100) == 4 || (code / 100) == 5) {
+ qWarning("request failed for %s: status code %d\n",
+ toCStr(reply_->url().toString()), code);
+ // Response code 400 means the link may have already expired.
+ if (code == 400 || !maybeRetry()) {
+ setHttpError(code);
+ emit finished(false);
+ return;
+ }
+ return;
+ }
+
+ onHttpRequestFinished();
+}
+
+bool FileServerTask::handleHttpRedirect()
+{
+ QVariant redirect_attr = reply_->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect_attr.isNull()) {
+ return false;
+ }
+
+ if (redirect_count_++ > kMaxRedirects) {
+ // simply treat too many redirects as server side error
+ setHttpError(500);
+ emit finished(false);
+ qWarning("too many redirects for %s\n",
+ toCStr(reply_->url().toString()));
+ return true;
+ }
+
+ url_ = redirect_attr.toUrl();
+ if (url_.isRelative()) {
+ url_ = reply_->url().resolved(url_);
+ }
+ qWarning("redirect to %s (from %s)\n", toCStr(url_.toString()),
+ toCStr(reply_->url().toString()));
+ reply_->deleteLater();
+ sendRequest();
+ return true;
+}
+
+
+GetFileTask::GetFileTask(const QUrl& url, const QString& local_path)
+ : FileServerTask(url, local_path),
+ tmp_file_(NULL)
+{
+}
+
+GetFileTask::~GetFileTask()
+{
+ if (tmp_file_) {
+ tmp_file_->remove();
+ delete tmp_file_;
+ }
+}
+
+void GetFileTask::prepare()
+{
+ QString download_tmp_dir = ::pathJoin(
+ seafApplet->configurator()->seafileDir(), kFileDownloadTmpDirName);
+ if (!::createDirIfNotExists(download_tmp_dir)) {
+ setError(FileNetworkTask::FileIOError, tr("Failed to create folders"));
+ emit finished(false);
+ return;
+ }
+
+ QString tmpf_path = ::pathJoin(download_tmp_dir, "seaf-XXXXXX");
+ tmp_file_ = new QTemporaryFile(tmpf_path);
+ tmp_file_->setAutoRemove(false);
+ if (!tmp_file_->open()) {
+ setError(FileNetworkTask::FileIOError, tr("Failed to create temporary files"));
+ emit finished(false);
+ }
+}
+
+void GetFileTask::sendRequest()
+{
+ QNetworkRequest request(url_);
+ reply_ = getQNAM()->get(request);
+
+ connect(reply_, SIGNAL(sslErrors(const QList<QSslError>&)),
+ this, SLOT(onSslErrors(const QList<QSslError>&)));
+
+ connect(reply_, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));
+ connect(reply_, SIGNAL(downloadProgress(qint64, qint64)),
+ this, SIGNAL(progressUpdate(qint64, qint64)));
+ connect(reply_, SIGNAL(finished()), this, SLOT(httpRequestFinished()));
+}
+
+void GetFileTask::httpReadyRead()
+{
+ if (canceled_) {
+ return;
+ }
+ // TODO: read in blocks (e.g 64k) instead of readAll
+ // TODO: check http status code
+ QByteArray chunk = reply_->readAll();
+ if (!chunk.isEmpty()) {
+ if (tmp_file_->write(chunk) <= 0) {
+ setError(FileNetworkTask::FileIOError, tr("Failed to create folders"));
+ emit finished(false);
+ }
+ }
+}
+
+void GetFileTask::onHttpRequestFinished()
+{
+ if (canceled_) {
+ return;
+ }
+ tmp_file_->close();
+
+ QString parent_dir = ::getParentPath(local_path_);
+ if (!::createDirIfNotExists(parent_dir)) {
+ setError(FileNetworkTask::FileIOError, tr("Failed to write file to disk"));
+ emit finished(false);
+ }
+
+ QFile oldfile(local_path_);
+ if (oldfile.exists() && !oldfile.remove()) {
+ setError(FileNetworkTask::FileIOError, tr("Failed to remove the older version of the downloaded file"));
+ emit finished(false);
+ return;
+ }
+
+ if (!tmp_file_->rename(local_path_)) {
+ setError(FileNetworkTask::FileIOError, tr("Failed to move file"));
+ emit finished(false);
+ return;
+ }
+
+ delete tmp_file_;
+ tmp_file_ = 0;
+ emit finished(true);
+}
+
+PostFilesTask::PostFilesTask(const QUrl& url,
+ const QString& parent_dir,
+ const QString& local_path,
+ const QStringList& names,
+ const bool use_relative)
+ : FileServerTask(url, local_path),
+ // work around with server
+ parent_dir_(parent_dir.endsWith('/') ? parent_dir : parent_dir + "/"),
+ name_(QFileInfo(local_path_).fileName()),
+ names_(names),
+ current_num_(-1),
+ progress_update_timer_(new QTimer(this)),
+ use_relative_(use_relative)
+{
+ // never used, set it to NULL to avoid segment fault
+ reply_ = NULL;
+ connect(progress_update_timer_, SIGNAL(timeout()), this, SLOT(onProgressUpdate()));
+}
+
+PostFilesTask::~PostFilesTask()
+{
+}
+
+void PostFilesTask::prepare()
+{
+ current_bytes_ = 0;
+ transferred_bytes_ = 0;
+ total_bytes_ = 0;
+
+ file_sizes_.reserve(names_.size());
+ Q_FOREACH(const QString &name, names_)
+ {
+ QString local_path = ::pathJoin(local_path_, name);
+ // approximate the bytes used by http protocol (e.g. the bytes of
+ // header)
+ qint64 file_size = QFileInfo(local_path).size() + 1024;
+ file_sizes_.push_back(file_size);
+ total_bytes_ += file_size;
+ }
+}
+
+void PostFilesTask::cancel()
+{
+ if (canceled_) {
+ return;
+ }
+ progress_update_timer_->stop();
+ canceled_ = true;
+ task_->cancel();
+}
+
+void PostFilesTask::sendRequest()
+{
+ startNext();
+}
+
+void PostFilesTask::onProgressUpdate()
+{
+ emit progressUpdate(current_bytes_ + transferred_bytes_, total_bytes_);
+}
+
+void PostFilesTask::onPostTaskProgressUpdate(qint64 bytes, qint64 /* sum_bytes */)
+{
+ current_bytes_ = bytes;
+}
+
+void PostFilesTask::onPostTaskFinished(bool success)
+{
+ if (canceled_) {
+ return;
+ }
+
+ if (!success) {
+ error_ = task_->error();
+ error_string_ = task_->errorString();
+ http_error_code_ = task_->httpErrorCode();
+ progress_update_timer_->stop();
+
+ const QString& file_path = names_[current_num_];
+ QString file_name = QFileInfo(file_path).fileName();
+ failed_path_ = file_name;
+
+ emit oneFileFailed(failed_path_, false);
+ return;
+ } else {
+ error_ = FileNetworkTask::NoError;
+ error_string_ = "";
+ http_error_code_ = 0;
+ progress_update_timer_->stop();
+ successful_names_ << names_[current_num_];
+ }
+
+ transferred_bytes_ += file_sizes_[current_num_];
+ startNext();
+}
+
+void PostFilesTask::startNext(const QString& link)
+{
+ progress_update_timer_->stop();
+ if (++current_num_ == names_.size()) {
+ emit finished(true);
+ return;
+ }
+ const QString& file_path = names_[current_num_];
+ QString file_name = QFileInfo(file_path).fileName();
+ current_name_ = file_name;
+ emit nameUpdate(current_name_);
+ QString relative_path;
+ if (use_relative_)
+ relative_path = ::pathJoin(QFileInfo(local_path_).fileName(), ::getParentPath(file_path));
+
+ // relative_path might be empty, and should be safe to use as well
+ if (!link.isEmpty()) {
+ url_ = link;
+ }
+ task_.reset(new ReliablePostFileTask(url_,
+ parent_dir_,
+ ::pathJoin(local_path_, file_path),
+ file_name,
+ relative_path));
+ connect(task_.data(), SIGNAL(progressUpdate(qint64, qint64)),
+ this, SLOT(onPostTaskProgressUpdate(qint64, qint64)));
+ connect(task_.data(), SIGNAL(finished(bool)),
+ this, SLOT(onPostTaskFinished(bool)));
+ current_bytes_ = 0;
+ progress_update_timer_->start(100);
+ task_->start();
+}
+
+void PostFilesTask::continueWithFailedFile(bool retry, const QString& link)
+{
+ if (retry) {
+ current_num_--;
+ } else {
+ // The user chooses to skip the failed file, but in order to keep the
+ // progress consistent, we need to pretend the file is already uploaded
+ // successfully.
+ transferred_bytes_ += file_sizes_[current_num_];
+ }
+ startNext(link);
+}
+
+void FileServerTask::setError(FileNetworkTask::TaskError error,
+ const QString& error_string)
+{
+ qWarning("[file server task] error: %s\n", toCStr(error_string));
+ error_ = error;
+ error_string_ = error_string;
+}
+
+void FileServerTask::setHttpError(int code)
+{
+ error_ = FileNetworkTask::ApiRequestError;
+ http_error_code_ = code;
+ if (code == 500) {
+ error_string_ = tr("Internal Server Error");
+ } else if (code == 443 || code == 520) {
+ // Handle the case when the storage quote is exceeded. It may happen in two cases:
+ //
+ // First, the quota has been used up before the upload. In such case
+ // seahub would return 520 to the generate-link request.
+ // See https://github.com/haiwen/seahub/blob/v6.0.7-server/seahub/api2/views.py#L133
+ //
+ // Second, the quota is not exceeded before the upload, but would exceed
+ // after the upload. In such case httpserver would return 443 to the
+ // multipart upload request.
+ // See https://github.com/haiwen/seafile-server/blob/v6.0.7-server/server/http-status-codes.h#L10
+ error_string_ = tr("The storage quota has been used up");
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIETN_FILEBROWSER_TAKS_H
+#define SEAFILE_CLIETN_FILEBROWSER_TAKS_H
+
+#include <QObject>
+#include <QUrl>
+#include <QMutex>
+
+#include "api/server-repo.h"
+#include "account.h"
+#include "file-browser-requests.h"
+
+class QTemporaryFile;
+class QFile;
+class QNetworkAccessManager;
+class QNetworkReply;
+class QThread;
+class QSslError;
+class QNetworkRequest;
+
+class FileServerTask;
+class ApiError;
+
+class ReliablePostFileTask;
+
+template<typename T> class QList;
+
+// deleter
+template<typename T>
+struct doDeleteLater
+{
+ static inline void cleanup(T *pointer) {
+ if (pointer != NULL)
+ pointer->deleteLater();
+ }
+};
+
+/**
+ * Handles file upload/download using seafile web api.
+ * The task contains two phases:
+ *
+ * First, we need to get the upload/download link for seahub.
+ * Second, we upload/download file to seafile fileserver with that link using
+ * a `FileServerTask`.
+ *
+ *
+ * In second phase, the FileServerTask is moved to a worker thread to execute,
+ * since we will do blocking file IO in that task.
+ *
+ * @abstract
+ */
+class FileNetworkTask: public QObject {
+ Q_OBJECT
+ friend class ReliablePostFileTask;
+public:
+ enum TaskType {
+ Upload,
+ Download
+ };
+
+ class Progress {
+ public:
+ Progress(qint64 transferred, qint64 total);
+ QString toString() const;
+ qint64 transferred, total;
+ };
+
+ FileNetworkTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path);
+
+ virtual ~FileNetworkTask();
+
+ void setAutoDelete(bool auto_delete) { auto_delete_ = auto_delete; }
+
+ // accessors
+ virtual TaskType type() const = 0;
+ const QString& repoId() const { return repo_id_; };
+ const Account& account() const { return account_; };
+ QString path() const { return path_; };
+ QString localFilePath() const { return local_path_; }
+ QString failedPath() const { return failed_path_; }
+ QString fileName() const;
+ QString oid() const { return oid_; }
+ QUrl url() const { return url_; }
+ Progress progress() const { return progress_; };
+ bool canceled() const { return canceled_; }
+ bool autoDelete() const { return auto_delete_; }
+
+ enum TaskError {
+ NoError = 0,
+ ApiRequestError,
+ FileIOError,
+ TaskCanceled
+ };
+ const TaskError& error() const { return error_; }
+ const QString& errorString() const { return error_string_; }
+ int httpErrorCode() const { return http_error_code_; }
+
+public slots:
+ virtual void start();
+ virtual void cancel();
+
+signals:
+ void progressUpdate(qint64 transferred, qint64 total);
+ void nameUpdate(QString current_name);
+ void finished(bool success);
+ void retried(int retry_count);
+
+protected slots:
+ void onFileServerTaskProgressUpdate(qint64 transferred, qint64 total);
+ void onFileServerTaskNameUpdate(QString current_name);
+ virtual void onLinkGet(const QString& link);
+ virtual void onGetLinkFailed(const ApiError& error);
+ virtual void startFileServerTask(const QString& link);
+ virtual void onFileServerTaskFinished(bool success);
+ virtual void onFinished(bool success);
+
+protected:
+ virtual void createGetLinkRequest() = 0;
+ virtual void createFileServerTask(const QString& link) = 0;
+
+ FileServerTask *fileserver_task_;
+ SeafileApiRequest *get_link_req_;
+
+ const Account account_;
+ const QString repo_id_;
+ QString path_;
+ QString local_path_;
+ QString failed_path_;
+ QString oid_;
+ QUrl url_;
+
+ TaskError error_;
+ QString error_string_;
+ int http_error_code_;
+ bool canceled_;
+
+ Progress progress_;
+ bool auto_delete_;
+
+ static QThread *worker_thread_;
+};
+
+
+/**
+ * The downloaded file is first written to a tmp location, then moved
+ * to its final location.
+ */
+class FileDownloadTask : public FileNetworkTask {
+ Q_OBJECT
+public:
+ FileDownloadTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ bool is_save_as_task);
+
+ TaskType type() const { return Download; }
+ QString fileId() const { return file_id_; }
+ bool isSaveAsTask() const { return is_save_as_task_; }
+
+protected:
+ void createFileServerTask(const QString& link);
+ void createGetLinkRequest();
+
+protected slots:
+ void onLinkGet(const QString& link);
+
+private:
+ const bool is_save_as_task_;
+ QString file_id_;
+};
+
+class FileUploadTask : public FileNetworkTask {
+ Q_OBJECT
+public:
+ FileUploadTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ const QString& name,
+ const bool use_upload = true,
+ const bool accept_user_confirmation = true);
+
+ // this copy constructor
+ // duplicate a task same with the old one, excluding its internal stage
+ FileUploadTask(const FileUploadTask& rhs);
+
+ void setAcceptUserConfirmation(bool accept) { accept_user_confirmation_ = accept ;}
+
+ // When a file fails to upload, we ask the user to confirm what he wants to
+ // do: retry/skip/abort.
+ //
+ // - abort: task->cancel()
+ // - retry: task->continueWithFailedFile(true)
+ // - skip: task->continueWithFailedFile(false)
+ void continueWithFailedFile(bool retry);
+
+ // Accessors
+ TaskType type() const { return Upload; }
+ const QString& name() const { return name_; }
+ bool useUpload() const { return use_upload_; }
+
+signals:
+ // This signal is meant to be listened by the file progress dialog.
+ void oneFileFailed(const QString& filename, bool single_file);
+
+protected slots:
+ // Here
+ virtual void onOneFileFailed(const QString& filename, bool single_file);
+ void onLinkGetAgain(const QString& link);
+
+protected:
+ virtual void startFileServerTask(const QString& link);
+ void createFileServerTask(const QString& link);
+ void createGetLinkRequest();
+
+ const QString name_;
+
+private:
+ // the copy assignment, delete it;
+ FileUploadTask &operator=(const FileUploadTask& rhs);
+
+ const bool use_upload_;
+ bool accept_user_confirmation_;
+ bool retry_;
+};
+
+class FileUploadMultipleTask : public FileUploadTask {
+ Q_OBJECT
+public:
+ FileUploadMultipleTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_dir_path,
+ const QStringList& names,
+ bool use_upload);
+
+ const QStringList& names() const { return names_; }
+ const QStringList& successfulNames();
+
+protected:
+ void createFileServerTask(const QString& link);
+
+ const QStringList names_;
+};
+
+class FileUploadDirectoryTask : public FileUploadTask {
+ Q_OBJECT
+public:
+ FileUploadDirectoryTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ const QString& name);
+
+protected:
+ void createFileServerTask(const QString& link);
+
+protected slots:
+ // overwrited
+ virtual void onFinished(bool success);
+
+private slots:
+ void nextEmptyFolder();
+ void onCreateDirFailed(const ApiError& error);
+
+private:
+ QStringList empty_subfolders_;
+ QScopedPointer<CreateDirectoryRequest, QScopedPointerDeleteLater> create_dir_req_;
+};
+
+/**
+ * Handles raw file download/upload with seafile file server.
+ *
+ * This is the base class for file upload/download task. The task runs in a
+ * seperate thread, which means we can not invoke non-const methods of it from
+ * the main thread. To start the task: use QMetaObject::invokeMethod to call
+ * the start() member function. task. The same for canceling the task.
+ *
+ * @abstract
+ */
+class FileServerTask : public QObject {
+ Q_OBJECT
+public:
+ FileServerTask(const QUrl& url,
+ const QString& local_path);
+ virtual ~FileServerTask();
+
+ virtual void continueWithFailedFile(bool retry, const QString& link) {};
+
+ // accessors
+ const FileNetworkTask::TaskError& error() const { return error_; }
+ const QString& errorString() const { return error_string_; }
+ int httpErrorCode() const { return http_error_code_; }
+ virtual const QString& oid() const { return oid_; }
+ int retryCount() const { return retry_count_; }
+ const QString& failedPath() const { return failed_path_; }
+ bool canceled() const { return canceled_; }
+ QUrl url() const { return url_; }
+
+ static void resetQNAM();
+
+signals:
+ void progressUpdate(qint64 transferred, qint64 total);
+ void nameUpdate(QString current_name);
+ void finished(bool success);
+ void retried(int retry_count);
+
+signals:
+ void oneFileFailed(const QString& filename, bool single_file);
+
+public slots:
+ void start();
+ virtual void cancel();
+
+protected slots:
+ void onSslErrors(const QList<QSslError>& errors);
+ void httpRequestFinished();
+ void retry();
+ void doAbort();
+
+protected:
+ /**
+ * Prepare the initialization work, like creating the tmp file, or open the
+ * uploaded file for reading. It may be called again when retrying a task.
+ */
+ virtual void prepare() = 0;
+
+ /**
+ * If return true, the request would be retried for a few times when error
+ * happened. By default the request is not retried. Subclasses can overwrite
+ * this function to enable retry.
+ */
+ virtual bool retryEnabled();
+
+ /**
+ * Send the http request.
+ * This member function may be called in two places:
+ * 1. when task is first started
+ * 2. when the request is redirected
+ */
+ virtual void sendRequest() = 0;
+ virtual void onHttpRequestFinished() = 0;
+ bool handleHttpRedirect();
+ bool maybeRetry();
+ void setError(FileNetworkTask::TaskError error, const QString& error_string);
+ void setHttpError(int code);
+
+ // Always use this to access the network access manager, instead of using
+ // network_mgr_ directly, because it handles the network status change
+ // detection.
+ QNetworkAccessManager *getQNAM();
+
+ QUrl url_;
+ QString local_path_;
+ QString failed_path_;
+ QString oid_;
+
+ QNetworkReply *reply_;
+ bool canceled_;
+ int redirect_count_;
+ int retry_count_;
+
+ FileNetworkTask::TaskError error_;
+ QString error_string_;
+ int http_error_code_;
+};
+
+class GetFileTask : public FileServerTask {
+ Q_OBJECT
+public:
+ GetFileTask(const QUrl& url, const QString& local_path);
+ ~GetFileTask();
+
+protected:
+ void prepare();
+ void sendRequest();
+ void onHttpRequestFinished();
+
+private slots:
+ void httpReadyRead();
+
+private:
+ QTemporaryFile *tmp_file_;
+};
+
+class PostFilesTask : public FileServerTask {
+ Q_OBJECT
+public:
+ PostFilesTask(const QUrl& url,
+ const QString& parent_dir,
+ const QString& local_path,
+ const QStringList& names,
+ const bool use_relative);
+ ~PostFilesTask();
+ int currentNum();
+
+ const QStringList& successfulNames() const { return successful_names_; }
+
+ void continueWithFailedFile(bool retry, const QString& link);
+
+protected:
+ void prepare();
+ void sendRequest();
+ void startNext(const QString& link = QString());
+
+private slots:
+ void cancel();
+ void onProgressUpdate();
+ void onPostTaskProgressUpdate(qint64, qint64);
+ void onPostTaskFinished(bool success);
+
+private:
+ // never used
+ void onHttpRequestFinished() {}
+
+ const QString parent_dir_;
+ const QString name_;
+ QList<qint64> file_sizes_;
+ const QStringList names_;
+ QStringList successful_names_;
+
+ QString current_name_;
+
+ QScopedPointer<ReliablePostFileTask, doDeleteLater<ReliablePostFileTask> > task_;
+ int current_num_;
+ // transferred bytes in the current tasks
+ qint64 current_bytes_;
+ // the total bytes of completely transferred tasks
+ qint64 transferred_bytes_;
+ // the total bytes of all tasks
+ qint64 total_bytes_;
+ // deal with the qt4 eventloop's bug
+ QTimer *progress_update_timer_;
+ const bool use_relative_;
+};
+
+#endif // SEAFILE_CLIETN_FILEBROWSER_TAKS_H
--- /dev/null
+#include <QDir>
+#include <QImage>
+#include <QQueue>
+#include <QHash>
+#include <QTimer>
+#include <QDateTime>
+
+#include "../seafile-applet.h"
+#include "../configurator.h"
+#include "../account-mgr.h"
+#include "../api/requests.h"
+#include "../utils/paint-utils.h"
+#include "../utils/utils.h"
+#include "../utils/file-utils.h"
+
+#include "thumbnail-service.h"
+
+static const int kCheckPendingInterval = 1000; // 1s
+static const qint64 kExpireTimeIntevalMsec = 300 * 1000; // 5min
+
+struct PendingRequestInfo {
+ int last_wait;
+ int time_to_wait;
+
+ void backoff() {
+ last_wait = qMax(last_wait, 1) * 2;
+ time_to_wait = last_wait;
+ }
+
+ bool isReady() {
+ return time_to_wait == 0;
+ }
+
+ void tick() {
+ time_to_wait = qMax(0, time_to_wait - 1);
+ }
+};
+
+struct ThumbnailKey {
+ QString repo_id;
+ QString path;
+ QString dirent_id;
+ uint size;
+
+ bool operator == (const ThumbnailKey &key) const {
+ return repo_id == key.repo_id &&
+ path == key.path &&
+ dirent_id == key.dirent_id &&
+ size == key.size;
+ }
+};
+
+uint qHash(const ThumbnailKey &key) {
+ QString size;
+ size.setNum(key.size);
+ const QString key_str = key.repo_id +
+ key.path +
+ key.dirent_id +
+ size;
+ return qHash(key_str);
+}
+
+class PendingThumbnailRequestQueue
+{
+public:
+ PendingThumbnailRequestQueue() {};
+
+ void enqueue(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+ {
+ ThumbnailKey key;
+ key.repo_id = repo_id;
+ key.path = path;
+ key.dirent_id = dirent_id;
+ key.size = size;
+
+ if (q_.contains(key)) {
+ return;
+ }
+ // if we have set an expire time, and we haven't reached it yet
+ if (expire_time_.contains(key) &&
+ QDateTime::currentMSecsSinceEpoch() <= expire_time_[key]) {
+ return;
+ }
+ // update expire time
+ expire_time_[key] = QDateTime::currentMSecsSinceEpoch() + kExpireTimeIntevalMsec;
+
+ q_.enqueue(key);
+ }
+
+ void enqueueAndBackoff(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+ {
+ ThumbnailKey key;
+ key.repo_id = repo_id;
+ key.path = path;
+ key.dirent_id = dirent_id;
+ key.size = size;
+
+ PendingRequestInfo& info = wait_[key];
+ info.backoff();
+
+ enqueue(repo_id, path, dirent_id, size);
+ }
+
+ void clearWait(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+ {
+ ThumbnailKey key;
+ key.repo_id = repo_id;
+ key.path = path;
+ key.dirent_id = dirent_id;
+ key.size = size;
+
+ wait_.remove(key);
+ }
+
+ void tick() {
+ if (q_.isEmpty())
+ return;
+
+ QListIterator<ThumbnailKey> iter(q_);
+
+ while (iter.hasNext()) {
+ ThumbnailKey key;
+ key.repo_id = iter.peekNext().repo_id;
+ key.path = iter.peekNext().path;
+ key.dirent_id = iter.peekNext().dirent_id;
+ key.size = iter.next().size;
+
+ if (wait_.contains(key)) {
+ PendingRequestInfo& info = wait_[key];
+ info.tick();
+ }
+ }
+ }
+
+ ThumbnailKey dequeue() {
+ ThumbnailKey key, key_default;
+ key_default.repo_id = QString();
+ key_default.path = QString();
+ key_default.dirent_id = QString();
+ key_default.size = 0;
+
+ int i = 0, n = q_.size();
+ while (i++ < n) {
+ if (q_.isEmpty()) {
+ return key_default;
+ }
+
+ key = q_.dequeue();
+
+ PendingRequestInfo info = wait_.value(key);
+ if (info.isReady()) {
+ return key;
+ } else {
+ q_.enqueue(key);
+ }
+ }
+
+ return key_default;
+ }
+
+ void reset() {
+ q_.clear();
+ wait_.clear();
+ expire_time_.clear();
+ }
+
+private:
+ QQueue<ThumbnailKey> q_;
+
+ QHash<ThumbnailKey, PendingRequestInfo> wait_;
+ QHash<ThumbnailKey, qint64> expire_time_;
+};
+
+ThumbnailService* ThumbnailService::singleton_ = NULL;
+
+ThumbnailService* ThumbnailService::instance()
+{
+ if (singleton_ == NULL) {
+ static ThumbnailService instance;
+ singleton_ = &instance;
+ }
+
+ return singleton_;
+}
+
+
+ThumbnailService::ThumbnailService(QObject *parent)
+ : QObject(parent),
+ get_thumbnail_req_(NULL)
+{
+ queue_ = new PendingThumbnailRequestQueue;
+
+ timer_ = new QTimer(this);
+
+ connect(timer_, SIGNAL(timeout()), this, SLOT(checkPendingRequests()));
+
+}
+
+void ThumbnailService::start()
+{
+ timer_->start(kCheckPendingInterval);
+}
+
+// check in-memory-cache
+QPixmap ThumbnailService::loadThumbnailFromLocal(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+{
+ QPixmap ret;
+
+ QString key = getPixmapCacheKey(repo_id, path, dirent_id, size);
+ if (cache_.find(key, &ret)) {
+ return ret;
+ }
+
+ return ret;
+}
+
+QString ThumbnailService::getPixmapCacheKey(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+{
+ const Account& account = seafApplet->accountManager()->accounts().front();
+ QString size_str;
+ size_str.setNum(size);
+ return QDir(thumbnails_dir_).filePath(::md5(account.serverUrl.host()
+ + account.username
+ + repo_id
+ + path
+ + dirent_id
+ + size_str));
+}
+
+void ThumbnailService::fetchImageFromServer(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+{
+ if (get_thumbnail_req_) {
+ if (repo_id == get_thumbnail_req_->repoId() &&
+ path == get_thumbnail_req_->path() &&
+ dirent_id == get_thumbnail_req_->direntId() &&
+ size == get_thumbnail_req_->size()) {
+ return;
+ }
+ queue_->enqueue(repo_id, path, dirent_id, size);
+ return;
+ }
+
+ const Account& account = seafApplet->accountManager()->accounts().front();
+
+ get_thumbnail_req_ = new GetThumbnailRequest(account,
+ repo_id,
+ path,
+ dirent_id,
+ size);
+
+ connect(get_thumbnail_req_, SIGNAL(success(const QPixmap&)),
+ this, SLOT(onGetThumbnailSuccess(const QPixmap&)));
+ connect(get_thumbnail_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetThumbnailFailed(const ApiError&)));
+
+ get_thumbnail_req_->send();
+}
+
+void ThumbnailService::onGetThumbnailSuccess(const QPixmap& img)
+{
+ const QString repo_id = get_thumbnail_req_->repoId();
+ const QString path_in_repo = get_thumbnail_req_->path();
+ const QString dirent_id = get_thumbnail_req_->direntId();
+ const uint size = get_thumbnail_req_->size();
+
+ QString key = getPixmapCacheKey(repo_id, path_in_repo, dirent_id, size);
+
+ cache_.insert(key, img);
+
+ emit thumbnailUpdated(img, path_in_repo);
+
+ get_thumbnail_req_->deleteLater();
+ get_thumbnail_req_ = NULL;
+
+ queue_->clearWait(repo_id, path_in_repo, dirent_id, size);
+}
+
+void ThumbnailService::onGetThumbnailFailed(const ApiError& error)
+{
+ const QString repo_id = get_thumbnail_req_->repoId();
+ const QString path = get_thumbnail_req_->path();
+ const QString dirent_id = get_thumbnail_req_->direntId();
+ const uint size = get_thumbnail_req_->size();
+
+ get_thumbnail_req_->deleteLater();
+ get_thumbnail_req_ = NULL;
+
+ queue_->enqueueAndBackoff(repo_id, path, dirent_id, size);
+}
+
+QPixmap ThumbnailService::getThumbnail(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size)
+{
+ QPixmap img = loadThumbnailFromLocal(repo_id, path, dirent_id, size);
+
+ // update all thumbnails if img is null
+ if (img.isNull()) {
+ if (!get_thumbnail_req_ ||
+ get_thumbnail_req_->repoId() != repo_id ||
+ get_thumbnail_req_->path() != path ||
+ get_thumbnail_req_->direntId() != dirent_id ||
+ get_thumbnail_req_->size() != size)
+ {
+ queue_->enqueue(repo_id, path, dirent_id, size);
+ }
+ }
+ if (img.isNull()) {
+ return QIcon(":/images/files_v2/file_image.png").pixmap(24);
+ } else {
+ return img;
+ }
+}
+
+void ThumbnailService::checkPendingRequests()
+{
+ queue_->tick();
+
+ if (get_thumbnail_req_ != NULL) {
+ return;
+ }
+
+ ThumbnailKey key = queue_->dequeue();
+ QString repo_id = key.repo_id;
+ QString path = key.path;
+ QString dirent_id = key.dirent_id;
+ uint size = key.size;
+ if (!repo_id.isEmpty()) {
+ fetchImageFromServer(repo_id, path, dirent_id, size);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_THUMBNAIL_SERVICE_H
+#define SEAFILE_CLIENT_THUMBNAIL_SERVICE_H
+
+#include <vector>
+#include <QObject>
+#include <QImage>
+#include <QPixmapCache>
+#include <QString>
+#include <QPixmap>
+
+class QTimer;
+
+class Account;
+class ApiError;
+class GetThumbnailRequest;
+class PendingThumbnailRequestQueue;
+
+
+class ThumbnailService : public QObject
+{
+ Q_OBJECT
+public:
+ static ThumbnailService* instance();
+
+ void start();
+
+ QPixmap getThumbnail(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint thumbnail_default_size = 28);
+
+signals:
+ void thumbnailUpdated(const QPixmap& thumbnail, const QString& path);
+
+private slots:
+ void onGetThumbnailSuccess(const QPixmap& thumbnail);
+ void onGetThumbnailFailed(const ApiError& error);
+ void checkPendingRequests();
+
+private:
+ Q_DISABLE_COPY(ThumbnailService)
+
+ ThumbnailService(QObject *parent=0);
+
+ static ThumbnailService *singleton_;
+
+ QPixmap loadThumbnailFromLocal(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size);
+ QString getPixmapCacheKey(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size);
+ void fetchImageFromServer(const QString& repo_id,
+ const QString& path,
+ const QString& dirent_id,
+ uint size);
+
+ GetThumbnailRequest *get_thumbnail_req_;
+
+ QString thumbnails_dir_;
+
+ QPixmapCache cache_;
+
+ PendingThumbnailRequestQueue *queue_;
+
+ QTimer *timer_;
+
+};
+
+#endif // SEAFILE_CLIENT_AVATAR_SERVICE_H
--- /dev/null
+#include <errno.h>
+#include <stdio.h>
+#include <sqlite3.h>
+
+#include <QDateTime>
+#include <QTimer>
+#include <QDir>
+
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "file-browser-requests.h"
+#include "tasks.h"
+#include "auto-update-mgr.h"
+#include "data-cache.h"
+#include "data-mgr.h"
+
+#include "transfer-mgr.h"
+
+namespace {
+
+bool isDownloadForGivenParentDir(FileDownloadTask* task,
+ const QString& repo_id,
+ const QString& parent_dir)
+{
+ return task && task->repoId() == repo_id &&
+ ::getParentPath(task->path()) == parent_dir;
+}
+
+bool matchDownloadTask(FileDownloadTask* task,
+ const QString& repo_id,
+ const QString& path)
+{
+ return task && task->repoId() == repo_id && task->path() == path;
+}
+
+} // namespace
+
+SINGLETON_IMPL(TransferManager)
+
+TransferManager::TransferManager()
+{
+}
+
+TransferManager::~TransferManager()
+{
+}
+
+FileDownloadTask* TransferManager::addDownloadTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ bool is_save_as_task)
+{
+ FileDownloadTask* existing_task = getDownloadTask(repo_id, path);
+ if (existing_task) {
+ return existing_task;
+ }
+
+ FileDownloadTask* task = new FileDownloadTask(account, repo_id, path, local_path, is_save_as_task);
+ connect(task, SIGNAL(finished(bool)),
+ this, SLOT(onDownloadTaskFinished(bool)));
+ if (current_download_) {
+ pending_downloads_.enqueue(task);
+ } else {
+ startDownloadTask(task);
+ }
+ return task;
+}
+
+void TransferManager::onDownloadTaskFinished(bool success)
+{
+ FileDownloadTask *task = (FileDownloadTask *)sender();
+ if (task == current_download_) {
+ current_download_ = nullptr;
+ if (!pending_downloads_.empty()) {
+ FileDownloadTask* task = pending_downloads_.dequeue();
+ startDownloadTask(task);
+ }
+ } else {
+ pending_downloads_.removeOne(task);
+ }
+}
+
+void TransferManager::startDownloadTask(FileDownloadTask* task)
+{
+ current_download_ = task;
+ task->start();
+}
+
+FileDownloadTask* TransferManager::getDownloadTask(const QString& repo_id,
+ const QString& path)
+{
+ qDebug("get download task repo_id is %s, path is %s",
+ repo_id.toUtf8().data(), path.toUtf8().data());
+ if (matchDownloadTask(current_download_, repo_id, path)) {
+ return current_download_;
+ }
+ foreach (FileDownloadTask* task, pending_downloads_) {
+ if (matchDownloadTask(task, repo_id, path)) {
+ return task;
+ }
+ }
+ return NULL;
+}
+
+void TransferManager::cancelDownload(const QString& repo_id,
+ const QString& path)
+{
+ FileDownloadTask* task = getDownloadTask(repo_id, path);
+ if (!task)
+ return;
+ // If the task is a pending one, it would be removed from queue in
+ // ::onDownloadTaskFinished slot.
+ task->cancel();
+}
+
+void TransferManager::cancelAllDownloadTasks()
+{
+ if (current_download_) {
+ current_download_->cancel();
+ current_download_= nullptr;
+ }
+ pending_downloads_.clear();
+}
+
+QList<FileDownloadTask*>
+TransferManager::getDownloadTasks(const QString& repo_id,
+ const QString& parent_dir)
+{
+ QList<FileDownloadTask*> tasks;
+ if (isDownloadForGivenParentDir(current_download_, repo_id, parent_dir)) {
+ tasks.append(current_download_);
+ }
+ foreach (FileDownloadTask* task, pending_downloads_) {
+ if (isDownloadForGivenParentDir(task, repo_id, parent_dir)) {
+ tasks.append(task);
+ }
+ }
+
+ return tasks;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_BROWSER_TRANSFER_MANAGER_H
+#define SEAFILE_CLIENT_FILE_BROWSER_TRANSFER_MANAGER_H
+
+#include <QObject>
+#include <QQueue>
+
+#include "api/api-error.h"
+#include "seaf-dirent.h"
+#include "utils/singleton.h"
+
+
+template<typename Key> class QQueue;
+
+class QThread;
+
+class Account;
+class SeafileApiRequest;
+class GetDirentsRequest;
+class DirentsCache;
+class FileCache;
+class FileUploadTask;
+class FileDownloadTask;
+class FileNetworkTask;
+
+/**
+ * TransferManager manages all upload/download tasks.
+ *
+ * There is a pending tasks queue for all download tasks. At any moment only
+ * one download task is running, others are waiting in the queue.
+ *
+ */
+class TransferManager : public QObject {
+ SINGLETON_DEFINE(TransferManager)
+ Q_OBJECT
+public:
+ TransferManager();
+ ~TransferManager();
+
+ FileDownloadTask* addDownloadTask(const Account& account,
+ const QString& repo_id,
+ const QString& path,
+ const QString& local_path,
+ bool is_save_as_task = false);
+
+ FileDownloadTask* getDownloadTask(const QString& repo_id,
+ const QString& path);
+
+ void cancelDownload(const QString& repo_id, const QString& path);
+ void cancelAllDownloadTasks();
+
+ /**
+ * Return all download tasks for files in the `parent_dir`
+ */
+ QList<FileDownloadTask*> getDownloadTasks(const QString& repo_id,
+ const QString& parent_dir);
+
+private slots:
+ void onDownloadTaskFinished(bool success);
+
+private:
+ void startDownloadTask(FileDownloadTask* task);
+
+ FileDownloadTask* current_download_;
+ QQueue<FileDownloadTask*> pending_downloads_;
+};
+
+
+#endif // SEAFILE_CLIENT_FILE_BROWSER_TRANSFER_MANAGER_H
--- /dev/null
+#include "finder-sync/finder-sync-host.h"
+
+#include <vector>
+#include <mutex>
+#include <memory>
+
+#include <QDir>
+#include <QFileInfo>
+
+#include "account.h"
+#include "account-mgr.h"
+#include "auto-login-service.h"
+#include "settings-mgr.h"
+#include "seafile-applet.h"
+#include "daemon-mgr.h"
+#include "rpc/local-repo.h"
+#include "rpc/rpc-client.h"
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/sharedlink-dialog.h"
+#include "filebrowser/seafilelink-dialog.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+
+enum PathStatus {
+ SYNC_STATUS_NONE = 0,
+ SYNC_STATUS_SYNCING,
+ SYNC_STATUS_ERROR,
+ SYNC_STATUS_IGNORED,
+ SYNC_STATUS_SYNCED,
+ SYNC_STATUS_READONLY,
+ SYNC_STATUS_PAUSED,
+ SYNC_STATUS_LOCKED,
+ SYNC_STATUS_LOCKED_BY_ME,
+ MAX_SYNC_STATUS,
+};
+
+namespace {
+struct QtLaterDeleter {
+public:
+ void operator()(QObject *ptr) {
+ ptr->deleteLater();
+ }
+};
+} // anonymous namespace
+
+static const char *const kPathStatus[] = {
+ "none", "syncing", "error", "ignored", "synced", "readonly", "paused", "locked", "locked_by_me", NULL,
+};
+
+static inline PathStatus getPathStatusFromString(const QString &status) {
+ for (int p = SYNC_STATUS_NONE; p < MAX_SYNC_STATUS; ++p)
+ if (kPathStatus[p] == status)
+ return static_cast<PathStatus>(p);
+ return SYNC_STATUS_NONE;
+}
+
+inline static bool isContainsPrefix(const QString &path,
+ const QString &prefix) {
+ if (prefix.size() > path.size())
+ return false;
+ if (!path.startsWith(prefix))
+ return false;
+ if (prefix.size() < path.size() && path[prefix.size()] != '/')
+ return false;
+ return true;
+}
+
+static std::mutex update_mutex_;
+static std::vector<LocalRepo> watch_set_;
+static std::unique_ptr<GetSharedLinkRequest, QtLaterDeleter> get_shared_link_req_;
+static std::unique_ptr<LockFileRequest, QtLaterDeleter> lock_file_req_;
+static std::unique_ptr<GetFileLockInfoRequest, QtLaterDeleter> get_lock_info_req_;
+static std::unique_ptr<GetUploadLinkRequest, QtLaterDeleter> get_upload_link_req_;
+
+FinderSyncHost::FinderSyncHost() : rpc_client_(new SeafileRpcClient) {
+ rpc_client_->tryConnectDaemon();
+ connect(seafApplet->daemonManager(), SIGNAL(daemonRestarted()), this, SLOT(onDaemonRestarted()));
+}
+
+FinderSyncHost::~FinderSyncHost() {
+ get_shared_link_req_.reset();
+ lock_file_req_.reset();
+}
+
+void FinderSyncHost::onDaemonRestarted()
+{
+ qDebug("reviving rpc client when daemon is restarted");
+ if (rpc_client_) {
+ delete rpc_client_;
+ }
+ rpc_client_ = new SeafileRpcClient();
+ rpc_client_->tryConnectDaemon();
+}
+
+utils::BufferArray FinderSyncHost::getWatchSet(size_t header_size,
+ int max_size) {
+ updateWatchSet(); // lock is inside
+
+ std::unique_lock<std::mutex> lock(update_mutex_);
+
+ std::vector<QByteArray> array;
+ size_t byte_count = header_size;
+
+ unsigned count = (max_size >= 0 && watch_set_.size() > (unsigned)max_size)
+ ? max_size
+ : watch_set_.size();
+ for (unsigned i = 0; i < count; ++i) {
+ const LocalRepo& repo = watch_set_[i];
+ QString internal_link_supported = repo.account.isAtLeastVersion(6, 3, 0)
+ ? "internal-link-supported"
+ : "internal-link-unsupported";
+ QString content = repo.worktree;
+ content += "\t" + internal_link_supported;
+ array.emplace_back(content.toUtf8());
+ byte_count += 36 + array.back().size() + 3;
+ }
+ // rount byte_count to longword-size
+ size_t round_end = byte_count & 3;
+ if (round_end)
+ byte_count += 4 - round_end;
+
+ utils::BufferArray retval;
+ retval.resize(byte_count);
+
+ // zeroize rounds
+ switch (round_end) {
+ case 1:
+ retval[byte_count - 3] = '\0';
+ case 2:
+ retval[byte_count - 2] = '\0';
+ case 3:
+ retval[byte_count - 1] = '\0';
+ default:
+ break;
+ }
+
+ assert(retval.size() == byte_count);
+ char *pos = retval.data() + header_size;
+ for (unsigned i = 0; i != count; ++i) {
+ // copy repo_id
+ memcpy(pos, watch_set_[i].id.toUtf8().data(), 36);
+ pos += 36;
+ // copy worktree
+ memcpy(pos, array[i].data(), array[i].size() + 1);
+ pos += array[i].size() + 1;
+ // copy status
+ *pos++ = watch_set_[i].sync_state;
+ *pos++ = '\0';
+ }
+
+ return retval;
+}
+
+void FinderSyncHost::updateWatchSet() {
+ std::unique_lock<std::mutex> lock(update_mutex_);
+
+ // update watch_set_
+ if (rpc_client_->listLocalRepos(&watch_set_)) {
+ qWarning("[FinderSync] update watch set failed");
+ watch_set_.clear();
+ return;
+ }
+ for (LocalRepo &repo : watch_set_) {
+ rpc_client_->getSyncStatus(repo);
+ repo.account = seafApplet->accountManager()->getAccountByRepo(repo.id, rpc_client_);
+ }
+ lock.unlock();
+}
+
+uint32_t FinderSyncHost::getFileStatus(const char *repo_id, const char *path) {
+ std::unique_lock<std::mutex> lock(update_mutex_);
+
+ QString repo = QString::fromUtf8(repo_id, 36);
+ QString path_in_repo = path;
+ QString status;
+ bool isDirectory = path_in_repo.endsWith('/');
+ if (isDirectory)
+ path_in_repo.resize(path_in_repo.size() - 1);
+ if (rpc_client_->getRepoFileStatus(
+ repo,
+ path_in_repo,
+ isDirectory, &status) != 0) {
+ return PathStatus::SYNC_STATUS_NONE;
+ }
+
+ return getPathStatusFromString(status);
+}
+
+void FinderSyncHost::doShareLink(const QString &path) {
+ QString repo_id;
+ Account account;
+ QString path_in_repo;
+ if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+ qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+ return;
+ }
+
+ get_shared_link_req_.reset(new GetSharedLinkRequest(
+ account, repo_id, QString("/").append(path_in_repo),
+ QFileInfo(path).isFile()));
+
+ connect(get_shared_link_req_.get(), SIGNAL(success(const QString &, const QString&)), this,
+ SLOT(onShareLinkGenerated(const QString &)));
+
+ get_shared_link_req_->send();
+}
+
+void FinderSyncHost::doInternalLink(const QString &path)
+{
+ QString repo_id;
+ Account account;
+ QString path_in_repo;
+ if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+ qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+ return;
+ }
+
+ GetSmartLinkRequest *req = new GetSmartLinkRequest(account, repo_id, path_in_repo, path_in_repo.endsWith('/'));
+ connect(req, SIGNAL(success(const QString&, const QString&)),
+ this, SLOT(onGetSmartLinkSuccess(const QString&, const QString&)));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetSmartLinkFailed(const ApiError&)));
+
+ req->send();
+}
+
+void FinderSyncHost::onGetSmartLinkSuccess(const QString& smart_link, const QString& protocol_link)
+{
+ SeafileLinkDialog *dialog = new SeafileLinkDialog(smart_link, protocol_link, nullptr);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void FinderSyncHost::onGetSmartLinkFailed(const ApiError& error)
+{
+ seafApplet->warningBox(tr("Failed to get link"));
+}
+
+void FinderSyncHost::doLockFile(const QString &path, bool lock)
+{
+ QString repo_id;
+ Account account;
+ QString path_in_repo;
+ if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+ qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+ return;
+ }
+ lock_file_req_.reset(new LockFileRequest(account, repo_id, path_in_repo, lock));
+
+ connect(lock_file_req_.get(), SIGNAL(success()),
+ this, SLOT(onLockFileSuccess()));
+ lock_file_req_->send();
+}
+
+void FinderSyncHost::onShareLinkGenerated(const QString &link)
+{
+ SharedLinkDialog *dialog = new SharedLinkDialog(link, NULL);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void FinderSyncHost::onLockFileSuccess()
+{
+ LockFileRequest* req = qobject_cast<LockFileRequest*>(sender());
+ if (!req)
+ return;
+ rpc_client_->markFileLockState(req->repoId(), req->path(), req->lock());
+}
+
+bool FinderSyncHost::lookUpFileInformation(const QString &path, QString *repo_id, Account *account, QString *path_in_repo)
+{
+ QString worktree;
+ // work in a mutex
+ {
+ std::unique_lock<std::mutex> watch_set_lock(update_mutex_);
+ for (const LocalRepo &repo : watch_set_)
+ if (isContainsPrefix(path, repo.worktree)) {
+ *repo_id = repo.id;
+ worktree = repo.worktree;
+ break;
+ }
+ }
+ if (worktree.isEmpty() || repo_id->isEmpty())
+ return false;
+
+ *path_in_repo = QDir(worktree).relativeFilePath(path);
+ if (!path_in_repo->startsWith("/"))
+ *path_in_repo = "/" + *path_in_repo;
+ if (path.endsWith("/"))
+ *path_in_repo += "/";
+
+ // we have a empty path_in_repo representing the root of the directory,
+ // and we are okay!
+ if (path_in_repo->startsWith("."))
+ return false;
+
+ *account = seafApplet->accountManager()->getAccountByRepo(*repo_id);
+ if (!account->isValid())
+ return false;
+
+ return true;
+}
+
+void FinderSyncHost::doShowFileHistory(const QString &path)
+{
+ QString repo_id;
+ Account account;
+ QString path_in_repo;
+ if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+ qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+ return;
+ }
+ QUrl url = "/repo/file_revisions/" + repo_id + "/";
+ url = ::includeQueryParams(url, {{"p", path_in_repo}});
+ AutoLoginService::instance()->startAutoLogin(url.toString());
+}
+
+
+void FinderSyncHost::doShowFileLockedBy(const QString &path)
+{
+ QString repo_id;
+ Account account;
+ QString path_in_repo;
+ if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+ qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+ return;
+ }
+
+ // printf ("getting lock info for %s\n", toCStr(path));
+ get_lock_info_req_.reset(new GetFileLockInfoRequest(
+ account, repo_id, QString("/").append(path_in_repo)));
+
+ connect(get_lock_info_req_.get(), SIGNAL(success(bool, const QString&)), this,
+ SLOT(onGetFileLockInfoSuccess(bool, const QString &)));
+ connect(get_lock_info_req_.get(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onGetFileLockInfoFailed(const ApiError&)));
+
+ get_lock_info_req_->send();
+}
+
+void FinderSyncHost::onGetFileLockInfoSuccess(bool found, const QString& lock_owner)
+{
+ // printf ("found: %s, lock_owner: %s\n", found ? "true" : "false", toCStr(lock_owner));
+ const QString file = ::getBaseName(get_lock_info_req_->path());
+
+ if (found) {
+ seafApplet->messageBox(tr("File \"%1\" is locked by %2").arg(file, lock_owner));
+ } else {
+ seafApplet->messageBox(tr("Failed to get lock information for file \"%1\"").arg(file));
+ }
+}
+
+void FinderSyncHost::onGetFileLockInfoFailed(const ApiError& error)
+{
+ const QString file = ::getBaseName(get_lock_info_req_->path());
+ seafApplet->messageBox(tr("Failed to get lock information for file \"%1\"").arg(file));
+}
+
+void FinderSyncHost::doGetUploadLink(const QString &path)
+{
+ QString repo_id;
+ Account account;
+ QString path_in_repo;
+ if (!lookUpFileInformation(path, &repo_id, &account, &path_in_repo)) {
+ qWarning("[FinderSync] invalid path %s", path.toUtf8().data());
+ return;
+ }
+
+ // printf ("get upload link for %s\n", toCStr(path));
+ get_upload_link_req_.reset(new GetUploadLinkRequest(
+ account, repo_id, QString("/").append(path_in_repo)));
+
+ connect(get_upload_link_req_.get(), SIGNAL(success(const QString&)), this,
+ SLOT(onGetUploadLinkSuccess(const QString &)));
+ connect(get_upload_link_req_.get(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onGetUploadLinkFailed(const ApiError&)));
+
+ get_upload_link_req_->send();
+}
+
+void FinderSyncHost::onGetUploadLinkSuccess(const QString& upload_link)
+{
+ // printf ("get upload link is %s", toCStr(upload_link));
+ SharedLinkDialog *dialog = new SharedLinkDialog(upload_link, NULL, false);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void FinderSyncHost::onGetUploadLinkFailed(const ApiError& error)
+{
+ const QString file = ::getBaseName(get_upload_link_req_->path());
+ seafApplet->messageBox(tr("Failed to get upload link for file \"%1\"").arg(file));
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FINDER_SYNC_HOST_H_
+#define SEAFILE_CLIENT_FINDER_SYNC_HOST_H_
+#include <QObject>
+#include <QString>
+#include <cstdint>
+#include <vector>
+#include "utils/stl.h"
+#include "api/api-error.h"
+
+const int kPathMaxSize = 1024;
+
+class Account;
+class SeafileRpcClient;
+class FinderSyncHost : public QObject {
+ Q_OBJECT
+public:
+ FinderSyncHost();
+ ~FinderSyncHost();
+ // called from another thread
+ utils::BufferArray getWatchSet(size_t header_size, int max_size = -1);
+ // called from another thread
+ uint32_t getFileStatus(const char* repo_id, const char* path);
+private slots:
+ void onDaemonRestarted();
+ void updateWatchSet();
+ void doLockFile(const QString &path, bool lock);
+ void doShareLink(const QString &path);
+ void doInternalLink(const QString &path);
+ void onShareLinkGenerated(const QString& link);
+ void onLockFileSuccess();
+ void doShowFileHistory(const QString& path);
+ void doShowFileLockedBy(const QString& path);
+ void onGetFileLockInfoSuccess(bool found, const QString& lock_owner);
+ void onGetFileLockInfoFailed(const ApiError& error);
+ void onGetSmartLinkSuccess(const QString& smart_link, const QString& protocol_link);
+ void onGetSmartLinkFailed(const ApiError& error);
+ void doGetUploadLink(const QString& path);
+ void onGetUploadLinkSuccess(const QString& upload_link);
+ void onGetUploadLinkFailed(const ApiError& error);
+
+private:
+ bool lookUpFileInformation(const QString &path, QString *repo_id, Account *account, QString *path_in_repo);
+ SeafileRpcClient *rpc_client_;
+};
+
+#endif // SEAFILE_CLIENT_FINDER_SYNC_HOST_H_
--- /dev/null
+#ifndef SEAFILE_CLIENT_FINDER_SYNC_LISTENER_H_
+#define SEAFILE_CLIENT_FINDER_SYNC_LISTENER_H_
+
+/// \brief start the listener
+///
+void finderSyncListenerStart();
+
+/// \brief stop the listener
+///
+void finderSyncListenerStop();
+
+#endif // SEAFILE_CLIENT_FINDER_SYNC_LISTENER_H_
--- /dev/null
+#include "finder-sync/finder-sync-host.h"
+#include "finder-sync/finder-sync-listener.h"
+
+#include <libkern/OSAtomic.h>
+#include <mach/mach.h>
+#import <Cocoa/Cocoa.h>
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+@interface FinderSyncListener : NSObject <NSMachPortDelegate>
+@end
+//
+// MachPort Message
+// - mach_msg_header_t command
+// - uint32_t version
+// - uint32_t command
+// - body
+// - mach_msg_trailer_t trailer (for rcv only)
+//
+//
+
+namespace {
+enum CommandType : uint32_t {
+ GetWatchSet = 0,
+ DoShareLink = 1,
+ DoGetFileStatus = 2,
+ DoInternalLink = 3,
+ DoLockFile = 4,
+ DoUnlockFile = 5,
+ DoShowFileHistory = 6,
+ DoShowFileLockedBy = 7,
+ DoGetUploadLink = 8,
+};
+
+struct mach_msg_command_send_t {
+ mach_msg_header_t header;
+ uint32_t version;
+ uint32_t command;
+ char repo[36];
+ char body[kPathMaxSize];
+};
+
+struct mach_msg_command_rcv_t {
+ mach_msg_header_t header;
+ uint32_t version;
+ uint32_t command;
+ char repo[36];
+ char body[kPathMaxSize];
+ mach_msg_trailer_t trailer;
+};
+
+struct mach_msg_file_status_send_t {
+ mach_msg_header_t header;
+ uint32_t version;
+ uint32_t command;
+ uint32_t status;
+};
+
+struct QtLaterDeleter {
+public:
+ void operator()(QObject *ptr) {
+ ptr->deleteLater();
+ }
+};
+} // anonymous namespace
+
+static NSString *const kFinderSyncMachPort = @"com.seafile.seafile-client.findersync.machport";
+// listener related
+static NSThread *finder_sync_listener_thread_ = nil;
+// atomic value
+static volatile int32_t finder_sync_started_ = 0;
+static FinderSyncListener *finder_sync_listener_ = nil;
+static std::unique_ptr<FinderSyncHost, QtLaterDeleter> finder_sync_host_;
+static constexpr uint32_t kFinderSyncProtocolVersion = 0x00000004;
+
+static void handleGetFileStatus(mach_msg_command_rcv_t* msg) {
+ // generate reply
+ mach_port_t port = msg->header.msgh_remote_port;
+ if (!port)
+ return;
+ mach_msg_file_status_send_t reply_msg;
+ bzero(&reply_msg, sizeof(mach_msg_header_t));
+ mach_msg_header_t *reply_msg_header =
+ reinterpret_cast<mach_msg_header_t*>(&reply_msg);
+ reply_msg_header->msgh_id = msg->header.msgh_id + 1;
+ reply_msg_header->msgh_size = sizeof(mach_msg_file_status_send_t);
+ reply_msg_header->msgh_local_port = MACH_PORT_NULL;
+ reply_msg_header->msgh_remote_port = port;
+ reply_msg_header->msgh_bits = MACH_MSGH_BITS_REMOTE(msg->header.msgh_bits);
+ reply_msg.status = finder_sync_host_->getFileStatus(msg->repo, msg->body);
+
+ // send the reply
+ kern_return_t kr = mach_msg_send(reply_msg_header);
+ if (kr != MACH_MSG_SUCCESS) {
+ qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+ // qWarning("[FinderSync] failed to send reply");
+ }
+
+ // destroy
+ mach_msg_destroy(reply_msg_header);
+}
+
+static void handleGetWatchSet(mach_msg_command_rcv_t* msg) {
+ // generate reply
+ mach_port_t port = msg->header.msgh_remote_port;
+ if (!port)
+ return;
+ utils::BufferArray reply_msg =
+ finder_sync_host_->getWatchSet(sizeof(mach_msg_header_t));
+ bzero(reply_msg.data(), sizeof(mach_msg_header_t));
+ mach_msg_header_t *reply_msg_header =
+ reinterpret_cast<mach_msg_header_t*>(reply_msg.data());
+ reply_msg_header->msgh_id = msg->header.msgh_id + 1;
+ reply_msg_header->msgh_size = reply_msg.size();
+ reply_msg_header->msgh_local_port = MACH_PORT_NULL;
+ reply_msg_header->msgh_remote_port = port;
+ reply_msg_header->msgh_bits = MACH_MSGH_BITS_REMOTE(msg->header.msgh_bits);
+
+ // send the reply
+ kern_return_t kr = mach_msg_send(reply_msg_header);
+ if (kr != MACH_MSG_SUCCESS) {
+ qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+ // qWarning("[FinderSync] failed to send reply");
+ }
+
+ // destroy
+ mach_msg_destroy(reply_msg_header);
+}
+
+@interface FinderSyncListener ()
+@property(readwrite, nonatomic, strong) NSPort *listenerPort;
+@end
+
+@implementation FinderSyncListener
+- (instancetype)init {
+ self = [super init];
+ self.listenerPort = nil;
+ return self;
+}
+- (void)start {
+ NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
+ mach_port_t port = MACH_PORT_NULL;
+
+ kern_return_t kr =
+ mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
+ if (kr != KERN_SUCCESS) {
+ qWarning("[FinderSync] failed to allocate mach port");
+ qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+ kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE,
+ -1);
+ if (kr != KERN_SUCCESS) {
+ qDebug("[FinderSync] failed to deallocate mach port");
+ qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+ }
+ return;
+ }
+
+ kr = mach_port_insert_right(mach_task_self(), port, port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (kr != KERN_SUCCESS) {
+ qWarning("[FinderSync] failed to insert send right to mach port");
+ qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+ kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE,
+ -1);
+ if (kr != KERN_SUCCESS) {
+ qDebug("[FinderSync] failed to deallocate mach port");
+ qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+ }
+ qDebug("[FinderSync] failed to allocate send right tp local mach port");
+ return;
+ }
+ self.listenerPort =
+ [NSMachPort portWithMachPort:port
+ options:NSMachPortDeallocateReceiveRight];
+ if (![[NSMachBootstrapServer sharedInstance]
+ registerPort:self.listenerPort
+ name:kFinderSyncMachPort]) {
+ [self.listenerPort invalidate];
+ qWarning("[FinderSync] failed to register mach port");
+ qDebug("[FinderSync] mach error %s", mach_error_string(kr));
+ return;
+ }
+ qDebug("[FinderSync] mach port registered");
+ [self.listenerPort setDelegate:self];
+ [runLoop addPort:self.listenerPort forMode:NSDefaultRunLoopMode];
+ while (finder_sync_started_)
+ [runLoop runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]];
+ [self.listenerPort invalidate];
+ qDebug("[FinderSync] mach port unregistered");
+ kr = mach_port_deallocate(mach_task_self(), port);
+ if (kr != KERN_SUCCESS) {
+ qDebug("[FinderSync] failed to deallocate mach port %u", port);
+ return;
+ }
+}
+- (void)stop {
+ CFRunLoopStop(CFRunLoopGetCurrent());
+}
+
+- (void)handleMachMessage:(void *)machMessage {
+ mach_msg_command_rcv_t *msg =
+ static_cast<mach_msg_command_rcv_t *>(machMessage);
+ if (msg->header.msgh_size != sizeof(mach_msg_command_send_t)) {
+ qWarning("[FinderSync] received msg with bad size %u", msg->header.msgh_size);
+ mach_msg_destroy(&msg->header);
+ return;
+ }
+
+ if (msg->version != kFinderSyncProtocolVersion) {
+ NSLog(@"FinderSync incompatible message protocol version %u", msg->version);
+ qWarning("[FinderSync] incompatible message protocol version %u", msg->version);
+ mach_msg_destroy(&msg->header);
+ // we need to quit before it cause more serious issue!
+ finderSyncListenerStop();
+ return;
+ }
+
+ switch (msg->command) {
+ case GetWatchSet:
+ handleGetWatchSet(msg);
+ break;
+ case DoShareLink:
+ // handle DoShareLink
+ QMetaObject::invokeMethod(finder_sync_host_.get(), "doShareLink",
+ Qt::QueuedConnection,
+ Q_ARG(QString, msg->body));
+ break;
+ case DoInternalLink:
+ // handle DoShareLink
+ QMetaObject::invokeMethod(finder_sync_host_.get(), "doInternalLink",
+ Qt::QueuedConnection,
+ Q_ARG(QString, msg->body));
+ break;
+ case DoGetFileStatus:
+ handleGetFileStatus(msg);
+ break;
+ case DoLockFile:
+ QMetaObject::invokeMethod(finder_sync_host_.get(), "doLockFile",
+ Qt::QueuedConnection,
+ Q_ARG(QString, msg->body),
+ Q_ARG(bool, true));
+ break;
+ case DoUnlockFile:
+ QMetaObject::invokeMethod(finder_sync_host_.get(), "doLockFile",
+ Qt::QueuedConnection,
+ Q_ARG(QString, msg->body),
+ Q_ARG(bool, false));
+ break;
+ case DoShowFileHistory:
+ QMetaObject::invokeMethod(finder_sync_host_.get(), "doShowFileHistory",
+ Qt::QueuedConnection,
+ Q_ARG(QString, msg->body));
+ break;
+ case DoShowFileLockedBy:
+ QMetaObject::invokeMethod(finder_sync_host_.get(), "doShowFileLockedBy",
+ Qt::QueuedConnection,
+ Q_ARG(QString, msg->body));
+ break;
+ case DoGetUploadLink:
+ QMetaObject::invokeMethod(finder_sync_host_.get(), "doGetUploadLink",
+ Qt::QueuedConnection,
+ Q_ARG(QString, msg->body));
+ break;
+ default:
+ qWarning("[FinderSync] received unknown command %u", msg->command);
+ break;
+ }
+ mach_msg_destroy(&msg->header);
+}
+
+@end
+
+void finderSyncListenerStart() {
+ if (!OSAtomicAdd32Barrier(0, &finder_sync_started_)) {
+ // this value is used in different threads
+ // keep it in atomic and guarenteed by barrier for safety
+ OSAtomicIncrement32Barrier(&finder_sync_started_);
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ finder_sync_host_.reset(new FinderSyncHost);
+ finder_sync_listener_ = [[FinderSyncListener alloc] init];
+ finder_sync_listener_thread_ =
+ [[NSThread alloc] initWithTarget:finder_sync_listener_
+ selector:@selector(start)
+ object:nil];
+ [finder_sync_listener_thread_ start];
+ });
+ }
+}
+
+void finderSyncListenerStop() {
+ if (OSAtomicAdd32Barrier(0, &finder_sync_started_)) {
+ // this value is used in different threads
+ // keep it in atomic and guarenteed by barrier for safety
+ OSAtomicDecrement32Barrier(&finder_sync_started_);
+
+ // tell finder_sync_listener_ to exit
+ [finder_sync_listener_ performSelector:@selector(stop)
+ onThread:finder_sync_listener_thread_
+ withObject:nil
+ waitUntilDone:NO];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ finder_sync_host_.reset();
+ });
+ }
+}
--- /dev/null
+#include <QStringList>
+#include <QDir>
+#include <QFileInfo>
+#include <QProcess>
+#include <QDebug>
+#include "finder-sync/finder-sync.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+
+static const char* kApplePluginkitBinary = "/usr/bin/pluginkit";
+static const char* kFinderSyncBundleIdentifier = "com.seafile.seafile-client.findersync";
+
+// run command and arugments,
+// and return the termination status
+// if we have non-null output, we will write stdout (not stderr) output to it
+static int runAsCommand(const QString &binary, const QStringList &arguments, QString
+ *output = nullptr) {
+ QProcess process;
+ process.start(binary, arguments);
+ if (!process.waitForFinished(500))
+ return false;
+ if (output)
+ *output = process.readAllStandardOutput().trimmed();
+ return process.exitCode();
+}
+
+static inline QString pluginPath() {
+#ifdef XCODE_APP
+ return QDir(utils::mac::mainBundlePath()).filePath("Contents/PlugIns/Seafile FinderSync.appex");
+#else
+ return QDir(utils::mac::mainBundlePath()).filePath("fsplugin/Seafile FinderSync.appex");
+#endif
+}
+
+/// \brief list all installed plugins
+static bool installedPluginPath(QString *path) {
+ QStringList arguments {"-m", "-v", "-i", kFinderSyncBundleIdentifier};
+ int status = runAsCommand(kApplePluginkitBinary, arguments, path);
+ if (status != 0 || path->isEmpty())
+ return false;
+ int begin = path->indexOf('/');
+ if (begin == -1)
+ return false;
+ int end = path->indexOf('\n', begin);
+ if (end == -1 || end - begin < 0)
+ return false;
+ *path = QStringRef(path, begin, end - begin).toString();
+
+ qDebug("[FinderSync] found installed plugin %s", path->toUtf8().data());
+
+ return true;
+}
+
+bool FinderSyncExtensionHelper::isInstalled() {
+ QString output;
+ QStringList arguments {"-m", "-i", kFinderSyncBundleIdentifier};
+ int status = runAsCommand(kApplePluginkitBinary, arguments, &output);
+ if (status != 0 || output.isEmpty())
+ return false;
+
+ return true;
+}
+
+bool FinderSyncExtensionHelper::isEnabled() {
+ QString output;
+ QStringList arguments {"-m", "-i", kFinderSyncBundleIdentifier};
+ int status = runAsCommand(kApplePluginkitBinary, arguments, &output);
+ if (status != 0 || output.isEmpty())
+ return false;
+ if (output[0] != '+' && output[0] != '?')
+ return false;
+
+ return true;
+}
+
+bool FinderSyncExtensionHelper::isBundled() {
+ QString plugin_path = pluginPath();
+ if (!QFileInfo(plugin_path).isDir()) {
+ qDebug("[FinderSync] unable to find bundled plugin at %s", plugin_path.toUtf8().data());
+ return false;
+ }
+
+ qDebug("[FinderSync] found bundled plugin at %s", plugin_path.toUtf8().data());
+ return true;
+}
+
+// Developer notes:
+// In Mac OSX Sierra and higher, to install a finder plugin (a .appex folder) ,
+// two conditions must be satisfied:
+// - the plugin must be signed
+// - the plugin must be included as part of a .app
+// So when seadrive-gui is not compiled with xcode, there is no way to install
+// the plugin.
+#ifdef XCODE_APP
+bool FinderSyncExtensionHelper::reinstall(bool force) {
+ if (!isBundled())
+ return false;
+
+ QString bundled_plugin_path = pluginPath();
+ QString plugin_path;
+ QStringList remove_arguments;
+
+ // remove all installed plugins
+ while(installedPluginPath(&plugin_path)) {
+ if (!force && bundled_plugin_path == plugin_path) {
+ qDebug("[FinderSync] current plugin detected: %s",
+ bundled_plugin_path.toUtf8().data());
+ return true;
+ }
+ remove_arguments = QStringList {"-r", plugin_path};
+ // this command returns non-zero when succeeds,
+ // so don't bother to check it
+ runAsCommand(kApplePluginkitBinary, remove_arguments);
+ }
+
+ QStringList install_arguments {"-a", bundled_plugin_path};
+ int status = runAsCommand(kApplePluginkitBinary, install_arguments);
+ if (status != 0)
+ return false;
+
+ qWarning("[FinderSync] reinstalled");
+ return true;
+}
+#else
+bool FinderSyncExtensionHelper::reinstall(bool force) {
+ return false;
+}
+#endif
+
+bool FinderSyncExtensionHelper::setEnable(bool enable) {
+ const char *election = enable ? "use" : "ignore";
+ QStringList arguments {"-e", election, "-i", kFinderSyncBundleIdentifier};
+ int status = runAsCommand(kApplePluginkitBinary, arguments);
+ if (status != 0)
+ return false;
+
+ return true;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FINDER_SYNC_H_
+#define SEAFILE_CLIENT_FINDER_SYNC_H_
+
+class FinderSyncExtensionHelper {
+public:
+ /// \brief check if plugin is installed
+ /// return true if installed
+ ///
+ static bool isInstalled();
+
+ /// \brief check if plugin is enabled
+ /// return true if enabled
+ /// this value can be changed via preference by user
+ static bool isEnabled();
+
+ /// \brief check if plugin has been bundled
+ /// return true if bundled
+ ///
+ static bool isBundled();
+
+ /// \brief do reinstall for the bundled plugin
+ /// return true if success
+ ///
+ static bool reinstall(bool force = false);
+
+ /// \brief change the plugin's status
+ /// return ture if success
+ ///
+ static bool setEnable(bool enable);
+};
+
+#endif // SEAFILE_CLIENT_FINDER_SYNC_H_
--- /dev/null
+#include <glib.h>
+#include <QTranslator>
+#include <QLibraryInfo>
+#include <QApplication>
+#include <QSettings>
+#include <QDebug>
+
+#include "i18n.h"
+
+namespace {
+const char* langs[] = {
+ NULL, //reserved for system locale
+ "ca",
+ "de_DE",
+ "en",
+ "es",
+ "es_AR",
+ "es_MX",
+ "fr_FR",
+ "he_IL",
+ "hu_HU",
+ "is",
+ "it",
+ "ko_KR",
+ "nl_BE",
+ "pl_PL",
+ "pt_BR",
+ "pt_PT",
+ "ru",
+ "sk_SK",
+ "uk",
+ "zh_CN",
+ "zh_TW",
+ "tr",
+ "nl_NL",
+ "lv",
+ "ja",
+ "sv",
+ "cs_CZ",
+ "el_GR",
+ "nb_NO",
+ NULL
+ };
+void saveCurrentLanguage(int langIndex) {
+ QSettings settings;
+
+ settings.beginGroup("Language");
+ settings.setValue("current", QString(langs[langIndex]));
+ settings.endGroup();
+}
+
+int loadCurrentLanguage() {
+ QSettings settings;
+
+ settings.beginGroup("Language");
+ QString current = settings.value("current").toString();
+ settings.endGroup();
+
+ // system locale
+ if (current.isEmpty()) {
+ return 0;
+ }
+
+ const char** pos = langs; /* skip first one*/
+ while(*++pos != NULL) {
+ if (*pos == current)
+ break;
+ }
+ return pos - langs;
+}
+
+} // anonymous namespace
+
+I18NHelper *I18NHelper::instance_ = NULL;
+
+I18NHelper::I18NHelper()
+ : qt_translator_(new QTranslator),
+ my_translator_(new QTranslator)
+{
+}
+
+I18NHelper::~I18NHelper() {
+}
+
+void I18NHelper::init() {
+ qApp->installTranslator(qt_translator_.data());
+ qApp->installTranslator(my_translator_.data());
+ int pos = preferredLanguage();
+ if (langs[pos] == NULL) // NULL is reserved for system locale
+ setLanguage(0);
+ else
+ setLanguage(pos);
+}
+
+int I18NHelper::preferredLanguage() {
+ return loadCurrentLanguage();
+}
+
+void I18NHelper::setPreferredLanguage(int langIndex) {
+ const QList<QLocale> &locales = getInstalledLocales();
+ if (langIndex < 0 || langIndex >= locales.size())
+ return;
+ saveCurrentLanguage(langIndex);
+}
+
+bool I18NHelper::setLanguage(int langIndex) {
+ const QList<QLocale> &locales = getInstalledLocales();
+ if (langIndex < 0 || langIndex >= locales.size())
+ return false;
+
+ const QLocale &locale = locales[langIndex];
+#if defined(Q_OS_WIN32)
+ qt_translator_->load("qt_" + locale.name());
+#else
+ qt_translator_->load("qt_" + locale.name(),
+ QLibraryInfo::location(QLibraryInfo::TranslationsPath));
+#endif
+
+ QString lang = QLocale::languageToString(locale.language());
+ printf("lang = %s, translation = %s, locale.name() = %s\n",
+ lang.toUtf8().data(),
+ langs[langIndex],
+ locale.name().toUtf8().data()
+ );
+ if (lang != "English") {
+ if (!my_translator_->load(locale, ":/i18n/seafile_")) {
+ printf ("failed to load in the first way\n");
+ my_translator_->load(
+ QString(":/i18n/seafile_%1.qm").arg(locale.name()));
+ }
+ }
+
+ return true;
+}
+
+const QList<QLocale> &I18NHelper::getInstalledLocales() {
+ static QList<QLocale> locales;
+ if (locales.empty()) {
+ locales.push_back(QLocale::system());
+ const char** next = langs; /* skip the first one*/
+ while(*++next != NULL)
+ locales.push_back(QLocale(*next));
+ }
+ return locales;
+}
+
+bool I18NHelper::isChinese()
+{
+ int lang_index = preferredLanguage();
+ if (lang_index < 0 || lang_index >= (int)G_N_ELEMENTS(langs))
+ return false;
+
+ if (lang_index == 0) {
+ // An index of 0 means seafile client is configured to use the system locale.
+ QLocale sys_locale = QLocale::system();
+ return sys_locale.country() == QLocale::China;
+ } else {
+ QString lang = QString(langs[lang_index]);
+ return lang == "zh_CN";
+ }
+}
--- /dev/null
+#ifndef _SEAF_I18N_H
+#define _SEAF_I18N_H
+#include <QList>
+#include <QLocale>
+#include <QStringList>
+#include <QScopedPointer>
+
+class QTranslator;
+class I18NHelper {
+public:
+ static I18NHelper* getInstance() {
+ if (!instance_) {
+ static I18NHelper i18n;
+ instance_ = &i18n;
+ }
+ return instance_;
+ }
+
+ void init();
+
+ QStringList getLanguages() {
+ QStringList languages;
+ Q_FOREACH(const QLocale& locale, getInstalledLocales())
+ {
+ languages.push_back(
+ QString("%1 - %2").arg(QLocale::languageToString(locale.language()))
+ .arg(QLocale::countryToString(locale.country())));
+ }
+ languages.front() = "-- System --";
+ return languages;
+ }
+
+ bool isChinese();
+ int preferredLanguage();
+ void setPreferredLanguage(int langIndex);
+private:
+ I18NHelper();
+ ~I18NHelper();
+ I18NHelper(const I18NHelper&); // = delete
+
+ const QList<QLocale> &getInstalledLocales();
+ bool setLanguage(int langIndex);
+ QScopedPointer<QTranslator> qt_translator_;
+ QScopedPointer<QTranslator> my_translator_;
+
+ static I18NHelper *instance_;
+};
+
+
+#endif // _SEAF_I18N_H
--- /dev/null
+
+#include <QtGlobal>
+
+#include <QSysInfo>
+#include <QThreadPool>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "account-mgr.h"
+
+#include "log-uploader.h"
+#include "JlCompress.h"
+#include "api/requests.h"
+
+namespace {
+
+const char* kGetUploadFileLink = "http://192.168.1.113:8000/api/v2.1/upload-links/dcfa5dd6645e4f38b823/upload/";
+const QString getLogUploadLink()
+{
+ QString upload_link = qgetenv("SEAFILE_LOG_UPLOAD_LINK");
+ return !upload_link.isEmpty() ? upload_link : kGetUploadFileLink;
+}
+
+} // namespace
+
+
+LogDirUploader::LogDirUploader()
+ : task_(nullptr)
+{
+}
+
+LogDirUploader::~LogDirUploader()
+{
+ if (task_) {
+ task_->deleteLater();
+ task_ = nullptr;
+ }
+}
+
+void LogDirUploader::start()
+{
+ progress_dlg_ = new LogUploadProgressDialog();
+ connect(progress_dlg_, SIGNAL(canceled()),
+ this, SLOT(onCanceled()));
+
+ LogDirCompressor *uploader = new LogDirCompressor;
+ connect(uploader, SIGNAL(compressFinished(bool, const QString&)),
+ this, SLOT(onCompressFinished(bool, const QString&)));
+ uploader->setAutoDelete(true);
+ QThreadPool::globalInstance()->start(uploader);
+}
+
+void LogDirUploader::onFinished()
+{
+ deleteLater();
+ if (progress_dlg_) {
+ progress_dlg_->accept();
+ progress_dlg_ = nullptr;
+ }
+}
+
+void LogDirUploader::onCanceled()
+{
+ if (task_) {
+ task_->cancel();
+ }
+ progress_dlg_ = nullptr;
+ if (QFile::exists(compressed_file_name_)) {
+ QFile::remove(compressed_file_name_);
+ }
+ onFinished();
+ emit finished();
+}
+
+void LogDirUploader::onCompressFinished(bool success, const QString& compressed_file_name)
+{
+ compressed_file_name_ = compressed_file_name;
+ if (success) {
+ SeafileApiRequest * get_upload_link_req = new GetUploadFileLinkRequest(getLogUploadLink());
+ connect(get_upload_link_req, SIGNAL(success(const QString&)),
+ this, SLOT(onGetUploadLinkSuccess(const QString&)));
+ connect(get_upload_link_req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetUploadLinkFailed(const ApiError&)));
+ get_upload_link_req->send();
+ } else {
+ seafApplet->warningBox(tr("Upload log files failed"));
+ onFinished();
+ }
+}
+
+void LogDirUploader::onGetUploadLinkSuccess(const QString& upload_link)
+{
+ if (progress_dlg_ == nullptr) {
+ if (QFile::exists(compressed_file_name_)) {
+ QFile::remove(compressed_file_name_);
+ }
+ return;
+ }
+ progress_dlg_->setWindowTitle(tr("Upload log files"));
+ QFile *file = new QFile(compressed_file_name_);
+ if (!file->exists()) {
+ qWarning("Upload %s failed. File does not exist.", toCStr(compressed_file_name_));
+ return;
+ }
+ if (!file->open(QIODevice::ReadOnly)) {
+ qWarning("Upload %s failed. Couldn't open file.", toCStr(compressed_file_name_));
+ return;
+ }
+ QString file_name = getBaseName(compressed_file_name_);
+ task_ = new PostFileTask(QUrl(upload_link), QString("/"),
+ compressed_file_name_, file, file_name, QString(), 0);
+ connect(task_, SIGNAL(finished(bool)), this, SLOT(onUploadLogDirFinished(bool)));
+ connect(task_, SIGNAL(progressUpdate(qint64, qint64)),
+ this, SLOT(onProgressUpdate(qint64, qint64)));
+
+ task_->start();
+}
+
+void LogDirUploader::onGetUploadLinkFailed(const ApiError &)
+{
+ qWarning("Get upload link failed.");
+ seafApplet->warningBox(tr("Upload log files failed"));
+ onFinished();
+}
+
+void LogDirUploader::onProgressUpdate(qint64 processed_bytes, qint64 total_bytes)
+{
+ if (total_bytes == 0) {
+ return;
+ }
+ if (task_->canceled()) {
+ return;
+ }
+ progress_dlg_->updateData(processed_bytes, total_bytes);
+}
+
+void LogDirUploader::onUploadLogDirFinished(bool success)
+{
+ if (task_->canceled()) {
+ return;
+ }
+
+ if (progress_dlg_) {
+ progress_dlg_ = nullptr;
+ }
+
+ if (!success) {
+ QString _error;
+ if (task_->httpErrorCode() == 403) {
+ _error = tr("Permission Error!");
+ } else if (task_->httpErrorCode() == 404) {
+ _error = tr("Library/Folder not found.");
+ } else if (task_->httpErrorCode() == 401) {
+ _error = tr("Authorization expired");
+ } else {
+ _error = task_->errorString();
+ }
+ QString msg = tr("Upload log files failed :%1").arg(_error);
+ seafApplet->warningBox(msg);
+ } else {
+
+ if (QFile::exists(compressed_file_name_)) {
+ QFile::remove(compressed_file_name_);
+ }
+ seafApplet->messageBox(tr("Successfully uploaded log files"));
+ }
+ onFinished();
+ emit finished();
+}
+
+LogUploadProgressDialog::LogUploadProgressDialog(QWidget *parent)
+ : QProgressDialog(parent)
+{
+ // set dialog attributes
+ setAttribute(Qt::WA_DeleteOnClose);
+ setWindowModality(Qt::NonModal);
+ setWindowTitle(tr("Compressing"));
+ setCancelButtonText(tr("Cancel"));
+ show();
+ raise();
+ activateWindow();
+}
+
+LogUploadProgressDialog::~LogUploadProgressDialog()
+{
+}
+
+void LogUploadProgressDialog::updateData(qint64 processed_bytes, qint64 total_bytes)
+{
+ if (total_bytes > INT_MAX) {
+ if (maximum() != INT_MAX) {
+ setMaximum(INT_MAX);
+ }
+
+ // Avoid overflow
+ double progress = double(processed_bytes) * INT_MAX / total_bytes;
+ setValue((int)progress);
+ } else {
+ if (maximum() != total_bytes) {
+ setMaximum(total_bytes);
+ }
+
+ setValue(processed_bytes);
+ }
+
+ setLabelText(tr("%1 of %2")
+ .arg(::readableFileSizeV2(processed_bytes))
+ .arg(::readableFileSizeV2(total_bytes)));
+}
+
+void LogDirCompressor::run() {
+ QString log_path = QDir(seafApplet->configurator()->ccnetDir()).absoluteFilePath("logs");
+ QString username = seafApplet->accountManager()->currentAccount().username;
+ QString time = QDateTime::currentDateTime().toString("yyyy.MM.dd-hh.mm.ss");
+ compressed_file_name_ = log_path + '-' + time + '-' + username + ".zip";
+
+ if (!JlCompress::compressDir(compressed_file_name_, log_path)) {
+ qWarning("create log archive failed");
+ emit compressFinished(false);
+ } else {
+ emit compressFinished(true, compressed_file_name_);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_LOG_UPLOADER_H
+#define SEAFILE_CLIENT_LOG_UPLOADER_H
+
+#include <QObject>
+#include <QRunnable>
+#include <QProgressDialog>
+#include "account.h"
+#include "filebrowser/reliable-upload.h"
+
+class LogUploadProgressDialog;
+class LogDirUploader : public QObject {
+ Q_OBJECT
+public:
+ LogDirUploader();
+ ~LogDirUploader();
+signals:
+ void finished();
+public slots:
+ virtual void start();
+private slots:
+ void onCanceled();
+ void onCompressFinished(bool success, const QString& compressed_file_name);
+ void onGetUploadLinkSuccess(const QString&);
+ void onGetUploadLinkFailed(const ApiError&);
+ void onUploadLogDirFinished(bool success);
+ void onProgressUpdate(qint64 processed_bytes, qint64 total_bytes);
+private:
+ void onFinished();
+ QString compressed_file_name_;
+ PostFileTask *task_;
+ LogUploadProgressDialog *progress_dlg_;
+};
+
+class LogUploadProgressDialog : public QProgressDialog {
+ Q_OBJECT
+public:
+ LogUploadProgressDialog(QWidget *parent=0);
+ ~LogUploadProgressDialog();
+ void updateData(qint64 processed_bytes, qint64 total_bytes);
+};
+
+
+class LogDirCompressor : public QObject, public QRunnable {
+ Q_OBJECT
+public:
+ LogDirCompressor() {};
+
+signals:
+ void compressFinished(bool success,
+ const QString& compressed_file_name = QString());
+
+public slots:
+ void run();
+
+private:
+ QString compressed_file_name_;
+ QProgressDialog *progress_dlg_;
+};
+#endif // SEAFILE_CLIENT_LOG_UPLOADER_H
--- /dev/null
+#ifndef SEAFILE_CLIENT_SPARKLE_SUPPORT_H
+#define SEAFILE_CLIENT_SPARKLE_SUPPORT_H
+
+class SparkleHelper {
+public:
+ static void checkForUpdate();
+ static void setAutoUpdateEnabled(bool enabled);
+ static bool autoUpdateEnabled();
+ static void setFeedURL(const char* url);
+};
+
+#endif // SEAFILE_CLIENT_SPARKLE_SUPPORT_H
--- /dev/null
+#include "mac-sparkle-support.h"
+
+#import "SUUpdater.h"
+
+void SparkleHelper::checkForUpdate()
+{
+ // [[SUUpdater sharedUpdater] checkForUpdatesInBackground];
+ [[SUUpdater sharedUpdater] checkForUpdates:nil];
+}
+
+void SparkleHelper::setAutoUpdateEnabled(bool enabled)
+{
+ [[SUUpdater sharedUpdater] setAutomaticallyChecksForUpdates: enabled];
+ // [[SUUpdater sharedUpdater] setAutomaticallyDownloadsUpdates: enabled];
+}
+
+void SparkleHelper::setFeedURL(const char* url)
+{
+ NSString *nsstr = [NSString stringWithCString:url
+ encoding:NSUTF8StringEncoding];
+ NSURL *feedURL = [NSURL URLWithString:nsstr];
+ [[SUUpdater sharedUpdater] setFeedURL: feedURL];
+}
+
+bool SparkleHelper::autoUpdateEnabled() {
+ return [[SUUpdater sharedUpdater] automaticallyChecksForUpdates];
+}
--- /dev/null
+#include <getopt.h>
+#include <QApplication>
+#include <QMessageBox>
+#include <QWidget>
+#include <QDir>
+
+#include <glib-object.h>
+#include <cstdio>
+
+#include "i18n.h"
+#include "crash-handler.h"
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "utils/process.h"
+#include "utils/uninstall-helpers.h"
+#include "ui/proxy-style.h"
+#include "seafile-applet.h"
+#include "QtAwesome.h"
+#include "open-local-helper.h"
+#if defined(Q_OS_WIN32)
+#include "utils/utils-win.h"
+#endif
+#if defined(Q_OS_MAC)
+#include "application.h"
+#endif
+
+#define APPNAME "seafile-applet"
+
+namespace {
+void initGlib()
+{
+#if !GLIB_CHECK_VERSION(2, 35, 0)
+ g_type_init();
+#endif
+#if !GLIB_CHECK_VERSION(2, 31, 0)
+ g_thread_init(NULL);
+#endif
+}
+
+void initBreakpad()
+{
+#ifdef SEAFILE_CLIENT_HAS_CRASH_REPORTER
+ // if we have built with breakpad, load it in run time
+ Breakpad::CrashHandler::instance()->Init(
+ QDir(defaultCcnetDir()).absoluteFilePath("crash-applet"));
+#endif
+}
+
+void setupFontFix()
+{
+#if QT_VERSION < QT_VERSION_CHECK(5, 3, 2) && defined(Q_OS_MAC)
+ // Text in buttons and drop-downs looks misaligned in osx 10.10,
+ // fixed in qt5.3.2
+ // https://bugreports.qt-project.org/browse/QTBUG-40833
+ if ( QSysInfo::MacintoshVersion > QSysInfo::MV_10_8 ) {
+ QFont::insertSubstitution(".Helvetica Neue DeskInterface", "Helvetica Neue");
+ }
+#endif // QT_VERSION_CHECK(5, 3, 2)
+}
+
+void setupHIDPIFix()
+{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 1, 0)
+ // enable builtin retina mode
+ // http://blog.qt.digia.com/blog/2013/04/25/retina-display-support-for-mac-os-ios-and-x11/
+ // https://qt.gitorious.org/qt/qtbase/source/a3cb057c3d5c9ed2c12fb7542065c3d667be38b7:src/gui/image/qicon.cpp#L1028-1043
+ qApp->setAttribute(Qt::AA_UseHighDpiPixmaps);
+#endif
+
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+ #if defined(Q_OS_WIN32)
+ if (!utils::win::fixQtHDPINonIntegerScaling()) {
+ qApp->setAttribute(Qt::AA_EnableHighDpiScaling);
+ }
+ #elif !defined(Q_OS_MAC)
+ // Enable HDPI auto detection.
+ // See http://blog.qt.io/blog/2016/01/26/high-dpi-support-in-qt-5-6/
+ qApp->setAttribute(Qt::AA_EnableHighDpiScaling);
+ #endif
+#endif
+}
+
+void setupSettingDomain()
+{
+ // see QSettings documentation
+ QCoreApplication::setOrganizationName(getBrand());
+ QCoreApplication::setOrganizationDomain("seafile.com");
+ QCoreApplication::setApplicationName(QString("%1 Client").arg(getBrand()));
+}
+
+void handleCommandLineOption(int argc, char *argv[])
+{
+ int c;
+ static const char *short_options = "KDXPc:d:f:";
+ static const struct option long_options[] = {
+ { "config-dir", required_argument, NULL, 'c' },
+ { "data-dir", required_argument, NULL, 'd' },
+ { "stop", no_argument, NULL, 'K' },
+ { "delay", no_argument, NULL, 'D' },
+ { "remove-user-data", no_argument, NULL, 'X' },
+ { "open-local-file", no_argument, NULL, 'f' },
+ { "stdout", no_argument, NULL, 'l' },
+ { "ping", no_argument, NULL, 'P' },
+ { NULL, 0, NULL, 0, },
+ };
+
+ while ((c = getopt_long (argc, argv, short_options,
+ long_options, NULL)) != EOF) {
+ switch (c) {
+ case 'c':
+ g_setenv ("CCNET_CONF_DIR", optarg, 1);
+ break;
+ case 'd':
+ g_setenv ("SEAFILE_DATA_DIR", optarg, 1);
+ break;
+ case 'l':
+ g_setenv ("LOG_STDOUT", "", 1);
+ break;
+ case 'K':
+ do_stop();
+ exit(0);
+ case 'P':
+ do_ping();
+ exit(0);
+ case 'D':
+ msleep(1000);
+ break;
+ case 'X':
+ do_remove_user_data();
+ exit(0);
+ case 'f':
+ OpenLocalHelper::instance()->handleOpenLocalFromCommandLine(optarg);
+ break;
+#if defined(HAVE_SPARKLE_SUPPORT) && defined(WINSPARKLE_DEBUG)
+ case 'U':
+ g_setenv ("SEAFILE_CLIENT_APPCAST_URI", optarg, 1);
+ break;
+#endif
+ default:
+ exit(1);
+ }
+ }
+
+}
+
+} // anonymous namespace
+
+int main(int argc, char *argv[])
+{
+ int ret = 0;
+
+ // call glib's init functions
+ initGlib();
+
+ // initialize breakpad if enabled
+#if defined(Q_OS_WIN32)
+ initBreakpad();
+#endif
+
+ // Apply hidpi support
+ setupHIDPIFix();
+
+#if defined(Q_OS_WIN32)
+ // When the user start seafile applet from the windows "Start" menu, the
+ // working directory is set to the parent folder of the seafile-applet.exe.
+ // See https://github.com/haiwen/seafile/blob/v6.0.1/msi/seafile.wxs#L60
+ //
+ // Sometimes the seafile-applet program would abort with error messgages
+ // "can't find qt plugin windows dll". So here we add current directory to
+ // the library path, hopefully fixing that problem.
+ QCoreApplication::addLibraryPath(".\\");
+#endif
+
+ // TODO imple if we have to restart the application
+ // the manual at http://qt-project.org/wiki/ApplicationRestart
+#if defined(Q_OS_MAC)
+ Application app(argc, argv);
+#else
+ QApplication app(argc, argv);
+#endif
+
+ // don't quit even if the last windows is closed
+ app.setQuitOnLastWindowClosed(false);
+
+ // apply some ui fixes for mac
+ setupFontFix();
+
+ // set the domains of settings
+ setupSettingDomain();
+
+ // initialize i18n settings
+ I18NHelper::getInstance()->init();
+
+ // initialize style settings
+ app.setStyle(new SeafileProxyStyle());
+
+ // start applet
+ SeafileApplet mApplet;
+ seafApplet = &mApplet;
+
+ // handle with the command arguments
+ handleCommandLineOption(argc, argv);
+
+ // count if we have any instance running now. if more than one, exit
+ if (count_process(APPNAME) > 1) {
+ if (OpenLocalHelper::instance()->activateRunningInstance()) {
+ printf("Activated running instance of seafile client\n");
+ return 0;
+ }
+ QMessageBox::warning(NULL, getBrand(),
+ QObject::tr("%1 Client is already running").arg(getBrand()),
+ QMessageBox::Ok);
+ return -1;
+ }
+
+ // init qtawesome component
+ awesome = new QtAwesome(qApp);
+ awesome->initFontAwesome();
+
+ seafApplet->start();
+
+ // qWarning("globalDevicePixelRatio() = %f\n", globalDevicePixelRatio());
+ // printf("globalDevicePixelRatio() = %f\n", globalDevicePixelRatio());
+ // fflush(stdout);
+
+ // start qt eventloop
+ ret = app.exec();
+
+ return ret;
+}
--- /dev/null
+#include <QTimer>
+#include <QDateTime>
+
+#include "utils/utils.h"
+#include "utils/translate-commit-desc.h"
+#include "utils/json-utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "daemon-mgr.h"
+#include "settings-mgr.h"
+#include "rpc/rpc-client.h"
+#include "rpc/sync-error.h"
+#include "ui/tray-icon.h"
+
+#include "message-poller.h"
+#include <seafile/seafile-error.h>
+
+namespace {
+
+const int kCheckNotificationIntervalMSecs = 1000;
+
+} // namespace
+
+struct SyncNotification {
+ QString type;
+ QString content;
+
+ static SyncNotification fromJson(const json_t* json);
+};
+
+
+MessagePoller::MessagePoller(QObject *parent): QObject(parent)
+{
+ rpc_client_ = new SeafileRpcClient();
+ check_notification_timer_ = new QTimer(this);
+ connect(check_notification_timer_, SIGNAL(timeout()), this, SLOT(checkNotification()));
+}
+
+MessagePoller::~MessagePoller()
+{
+ delete check_notification_timer_;
+ delete rpc_client_;
+}
+
+void MessagePoller::start()
+{
+ rpc_client_->tryConnectDaemon();
+ check_notification_timer_->start(kCheckNotificationIntervalMSecs);
+ connect(seafApplet->daemonManager(), SIGNAL(daemonDead()), this, SLOT(onDaemonDead()));
+ connect(seafApplet->daemonManager(), SIGNAL(daemonRestarted()), this, SLOT(onDaemonRestarted()));
+}
+
+void MessagePoller::onDaemonDead()
+{
+ qDebug("pausing message poller when daemon is dead");
+ check_notification_timer_->stop();
+}
+
+void MessagePoller::onDaemonRestarted()
+{
+ qDebug("reviving message poller when daemon is restarted");
+ if (rpc_client_) {
+ delete rpc_client_;
+ }
+ rpc_client_ = new SeafileRpcClient();
+ rpc_client_->tryConnectDaemon();
+ check_notification_timer_->start(kCheckNotificationIntervalMSecs);
+}
+
+void MessagePoller::checkNotification()
+{
+ json_t *ret;
+ if (!rpc_client_->getSyncNotification(&ret)) {
+ return;
+ }
+ SyncNotification notification = SyncNotification::fromJson(ret);
+ json_decref(ret);
+
+ processNotification(notification);
+}
+
+SyncNotification SyncNotification::fromJson(const json_t *root)
+{
+ SyncNotification notification;
+ Json json(root);
+
+ // char *s = json_dumps(root, 0);
+ // printf ("[%s] %s\n", QDateTime::currentDateTime().toString().toUtf8().data(), s);
+ // qWarning ("[%s] %s\n", QDateTime::currentDateTime().toString().toUtf8().data(), s);
+ // free (s);
+
+ notification.type = json.getString("type");
+ notification.content = json.getString("content");
+ return notification;
+}
+
+void MessagePoller::processNotification(const SyncNotification& notification)
+{
+ const QString& type = notification.type;
+ const QString& content = notification.content;
+ if (type == "transfer") {
+ // empty
+ } else if (type == "sync.done" ||
+ type == "sync.multipart_upload") {
+ /* format: a concatenation of (repo_name, repo_id, commmit_id,
+ * previous_commit_id, description), separated by tabs */
+ QStringList slist = content.split("\t");
+ if (slist.count() != 5) {
+ qWarning("Bad sync.done message format");
+ return;
+ }
+
+ QString title;
+ if (type == "sync.done")
+ title = tr("\"%1\" is synchronized").arg(slist.at(0));
+ else
+ title = tr("Files uploaded to \"%1\"").arg(slist.at(0));
+ QString repo_id = slist.at(1).trimmed();
+ QString commit_id = slist.at(2).trimmed();
+ QString previous_commit_id = slist.at(3).trimmed();
+ QString desc = slist.at(4).trimmed();
+
+ seafApplet->trayIcon()->showMessage(title, translateCommitDesc(desc), repo_id, commit_id, previous_commit_id);
+
+ } else if (type == "sync.error") {
+ json_error_t error;
+ json_t *object = json_loads(toCStr(content), 0, &error);
+ if (!object) {
+ qWarning("Failed to parse json: %s", error.text);
+ return;
+ }
+
+ QString repo_id = QString::fromUtf8(json_string_value(json_object_get(object, "repo_id")));
+ QString title = QString::fromUtf8(json_string_value(json_object_get(object, "repo_name")));
+ QString path = QString::fromUtf8(json_string_value(json_object_get(object, "path")));
+ int err_id = json_integer_value(json_object_get(object, "err_id"));
+ QString msg;
+ switch (err_id) {
+ case SYNC_ERROR_ID_FILE_LOCKED_BY_APP:
+ msg = tr("Failed to sync file %1\nFile is locked by other application. This file will be updated when you close the application.").arg(path);
+ break;
+ case SYNC_ERROR_ID_FOLDER_LOCKED_BY_APP:
+ msg = tr("Failed to sync folder %1\nSome file in this folder is locked by other application. This folder will be updated when you close the application.").arg(path);
+ break;
+ case SYNC_ERROR_ID_FILE_LOCKED:
+ msg = tr("Failed to sync file %1\nFile is locked by another user. Update to this file is not uploaded.").arg(path);
+ break;
+ case SYNC_ERROR_ID_INVALID_PATH:
+ msg = tr("Failed to sync %1\nFile path contains invalid characters. It is not synced to this computer.").arg(path);
+ break;
+ case SYNC_ERROR_ID_INDEX_ERROR:
+ msg = tr("Failed to index file %1\nPlease check file permission and disk space.").arg(path);
+ break;
+ case SYNC_ERROR_ID_PATH_END_SPACE_PERIOD:
+ msg = tr("Failed to sync %1\nFile path is ended with space or period and cannot be created on Windows.").arg(path);
+ break;
+ case SYNC_ERROR_ID_PATH_INVALID_CHARACTER:
+ msg = tr("Failed to sync %1\nFile path contains invalid characters. It is not synced to this computer.").arg(path);
+ break;
+ case SYNC_ERROR_ID_FOLDER_PERM_DENIED:
+ msg = tr("Update to file %1 is denied by folder permission setting.").arg(path);
+ break;
+ case SYNC_ERROR_ID_PERM_NOT_SYNCABLE:
+ msg = tr("No permission to sync folder %1.").arg(path);
+ break;
+ case SYNC_ERROR_ID_UPDATE_TO_READ_ONLY_REPO:
+ msg = tr("Updates in read-only library %1 will not be uploaded.").arg(path);
+ break;
+ case SYNC_ERROR_ID_CONFLICT:
+ msg = tr("Concurrent updates to file. File %1 is saved as conflict file").arg(path);
+ break;
+ case SYNC_ERROR_ID_REMOVE_UNCOMMITTED_FOLDER:
+ msg = tr("Folder %1 is moved to seafile-recycle-bin folder since it contains not-yet uploaded files.").arg(path);
+ break;
+ default:
+ qWarning("Unknown sync error id %d", err_id);
+ json_decref(object);
+ return;
+ }
+
+ seafApplet->trayIcon()->showMessage(title, msg, repo_id,
+ QString(""), QString(""), QSystemTrayIcon::Information, 10000, true);
+
+ json_decref(object);
+
+ } else if (type == "repo.remove") {
+ /* format : <repo_name> */
+ QString repo_name = content;
+ QString buf = tr("Folder for library %1 is removed or moved. The library is unsynced.").arg(repo_name);
+ seafApplet->trayIcon()->showMessage(getBrand(), buf);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_MESSAGE_POLLER_H
+#define SEAFILE_CLIENT_MESSAGE_POLLER_H
+
+#include <QObject>
+
+class QTimer;
+class SeafileRpcClient;
+
+struct SyncNotification;
+
+class MessagePoller : public QObject {
+ Q_OBJECT
+public:
+ MessagePoller(QObject *parent=0);
+ ~MessagePoller();
+
+ void start();
+
+private slots:
+ void onDaemonDead();
+ void onDaemonRestarted();
+ void checkNotification();
+
+private:
+ Q_DISABLE_COPY(MessagePoller)
+
+ void processNotification(const SyncNotification& notification);
+
+ SeafileRpcClient *rpc_client_;
+
+ QTimer *check_notification_timer_;
+};
+
+#endif // SEAFILE_CLIENT_MESSAGE_POLLER_H
--- /dev/null
+#include <QNetworkAccessManager>
+#include <QNetworkProxy>
+#include <algorithm>
+#include <QStringRef>
+#include <QSslConfiguration>
+#include <QSslSocket>
+#include <QSslCipher>
+#include <QTimer>
+#include <QMutexLocker>
+
+#include "utils/utils-mac.h"
+#include "api/api-client.h"
+#include "filebrowser/tasks.h"
+#include "server-status-service.h"
+
+#include "network-mgr.h"
+
+namespace {
+
+const int kCheckNetworkStatusIntervalMSecs = 10 * 1000; // 10s
+
+QNetworkProxy proxy_;
+
+template <class T, std::size_t N>
+inline size_t ArrayLengthOf(T (&)[N]) {
+ return N;
+}
+
+const char *const kWhitelistCiphers[] = {
+ "ECDHE-RSA-AES256-GCM-SHA384"
+ "ECDHE-RSA-AES128-GCM-SHA256"
+ "DHE-RSA-AES256-GCM-SHA384"
+ "DHE-RSA-AES128-GCM-SHA256"
+ "ECDHE-RSA-AES256-SHA384"
+ "ECDHE-RSA-AES128-SHA256"
+ "ECDHE-RSA-AES256-SHA"
+ "ECDHE-RSA-AES128-SHA"
+ "DHE-RSA-AES256-SHA256"
+ "DHE-RSA-AES128-SHA256"
+ "DHE-RSA-AES256-SHA"
+ "DHE-RSA-AES128-SHA"
+ "ECDHE-RSA-DES-CBC3-SHA"
+ "EDH-RSA-DES-CBC3-SHA"
+ "AES256-GCM-SHA384"
+ "AES128-GCM-SHA256"
+ "AES256-SHA256"
+ "AES128-SHA256"
+ "AES256-SHA"
+ "AES128-SHA"
+ "DES-CBC3-SHA"
+};
+
+// return false if it contains RC4, RSK, CBC, MD5, DES, DSS, EXPORT, NULL
+bool isWeakCipher(const QString& cipher_name)
+{
+ int current_begin = 0;
+ int current_end;
+ QStringRef name;
+ while((current_end = cipher_name.indexOf("-", current_begin)) != -1) {
+ name = QStringRef(&cipher_name, current_begin, current_end - current_begin);
+ if (name == "RC4")
+ return true;
+ else if (name == "PSK")
+ return true;
+ else if (name == "CBC")
+ return true;
+ else if (name == "MD5")
+ return true;
+ else if (name == "DES")
+ return true;
+ else if (name == "DSS")
+ return true;
+ else if (name == "EXP")
+ return true;
+ else if (name == "NULL")
+ return true;
+
+ current_begin = current_end + 1;
+ }
+ return false;
+}
+
+void disableWeakCiphers()
+{
+ QSslConfiguration configuration = QSslConfiguration::defaultConfiguration();
+ const QList<QSslCipher> ciphers = QSslSocket::supportedCiphers();
+
+ QList<QSslCipher> new_ciphers;
+ Q_FOREACH(const QSslCipher &cipher, ciphers)
+ {
+ bool whitelisted = false;
+ for (unsigned i = 0; i < ArrayLengthOf(kWhitelistCiphers); ++i) {
+ if (cipher.name() == kWhitelistCiphers[i]) {
+ whitelisted = true;
+ break;
+ }
+ }
+ if (!whitelisted) {
+ // blacklist eNULL, no encryption
+ if (cipher.encryptionMethod().isEmpty())
+ continue;
+ // blacklist aNULL, no authentication
+ if (cipher.authenticationMethod().isEmpty())
+ continue;
+ // blacklist RC4, RSK, CBC, MD5, DES, DSS, EXPORT, NULL
+ const QString cipher_name = cipher.name();
+ if (isWeakCipher(cipher_name))
+ continue;
+ }
+ new_ciphers.push_back(cipher);
+ }
+ configuration.setCiphers(new_ciphers);
+ QSslConfiguration::setDefaultConfiguration(configuration);
+}
+
+#ifdef Q_OS_MAC
+void loadUserCaCertificate()
+{
+ QList<QSslCertificate> certificates;
+ const std::vector<QByteArray> certs = utils::mac::getSystemCaCertificates();
+ for (unsigned i = 0; i < certs.size(); ++i)
+ {
+ certificates.append(QSslCertificate::fromData(certs[i], QSsl::Der));
+ }
+
+ // remove duplicates
+ certificates = certificates.toSet().toList();
+
+ QSslSocket::setDefaultCaCertificates(certificates);
+}
+#endif
+} // anonymous namespace
+
+NetworkManager* NetworkManager::instance_ = NULL;
+
+NetworkManager::NetworkManager() : should_retry_(true) {
+ // remove unsafe cipher
+ disableWeakCiphers();
+
+#ifdef Q_OS_MAC
+ // load user ca certificate from system, mac only
+ loadUserCaCertificate();
+#endif
+}
+
+void NetworkManager::addWatch(QNetworkAccessManager* manager)
+{
+ if (std::find(managers_.begin(), managers_.end(), manager) == managers_.end()) {
+ connect(manager, SIGNAL(destroyed()), this, SLOT(onCleanup()));
+ managers_.push_back(manager);
+ }
+}
+
+void NetworkManager::applyProxy(const QNetworkProxy& proxy)
+{
+ proxy_ = proxy;
+ should_retry_ = true;
+ QNetworkProxy::setApplicationProxy(proxy_);
+ for(std::vector<QNetworkAccessManager*>::iterator pos = managers_.begin();
+ pos != managers_.end(); ++pos)
+ (*pos)->setProxy(proxy_);
+ emit proxyChanged(proxy_);
+}
+
+void NetworkManager::reapplyProxy()
+{
+ applyProxy(proxy_);
+}
+
+void NetworkManager::onCleanup()
+{
+ // Don't use "qobject_cast<QNetworkAccessManager>" here, because the
+ // "destroyed" signal is emited by QObject class, so qobject_cast would fail
+ // to cast it to QNetworkAccessManager.
+ QNetworkAccessManager *manager = (QNetworkAccessManager*)(sender());
+ managers_.erase(std::remove(managers_.begin(), managers_.end(), manager),
+ managers_.end());
+}
+
+SINGLETON_IMPL(NetworkStatusDetector)
+
+NetworkStatusDetector::NetworkStatusDetector() {
+ has_network_failure_ = false;
+
+ check_timer_ = new QTimer(this);
+ connect(check_timer_, &QTimer::timeout, this, &NetworkStatusDetector::detect);
+}
+
+NetworkStatusDetector::~NetworkStatusDetector() {
+}
+
+void NetworkStatusDetector::start() {
+ qWarning("Starting the network status detector");
+ check_timer_->start(kCheckNetworkStatusIntervalMSecs);
+}
+
+void NetworkStatusDetector::stop() {
+ check_timer_->stop();
+}
+
+void NetworkStatusDetector::detect() {
+ bool need_reset = false;
+
+ {
+ QMutexLocker lock(&network_error_mutex_);
+ if (has_network_failure_) {
+ has_network_failure_ = false;
+ need_reset = true;
+ }
+ }
+
+ if (need_reset) {
+ qWarning("[network detector] resetting the qt network access manager");
+ SeafileApiClient::resetQNAM();
+ FileServerTask::resetQNAM();
+ ServerStatusService::instance()->refreshUnconnected();
+ }
+}
+
+// Whether the given error may indicate a network reset, e.g. when the
+// computer wakes up after sleeping/hibernating
+bool NetworkStatusDetector::shouldTreatErrorAsNetworkReset(QNetworkReply::NetworkError error)
+{
+ switch (error) {
+ case QNetworkReply::ConnectionRefusedError:
+ case QNetworkReply::SslHandshakeFailedError:
+ case QNetworkReply::RemoteHostClosedError:
+ return false;
+ default:
+ return true;
+ }
+}
+
+void NetworkStatusDetector::setNetworkFailure(QNetworkReply::NetworkError error) {
+ if (!shouldTreatErrorAsNetworkReset(error)) {
+ return;
+ }
+
+ QMutexLocker lock(&network_error_mutex_);
+ if (!has_network_failure_) {
+ qWarning("[network detector] got a network failure: %d", (int)error);
+ has_network_failure_ = true;
+ }
+}
+
+void NetworkStatusDetector::setNetworkSuccess() {
+ // TODO: what if the successful requests are for a local server?
+ // if (has_network_failure_) {
+ // qDebug("[network detector] got a network success");
+ // has_network_failure_ = false;
+ // }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_NETWORK_MANAGER_H
+#define SEAFILE_CLIENT_NETWORK_MANAGER_H
+
+#include <QObject>
+#include <vector>
+#include <QNetworkReply>
+#include <QMutex>
+
+#include "utils/singleton.h"
+
+class QNetworkAccessManager;
+class QNetworkProxy;
+class QTimer;
+
+class NetworkManager : public QObject {
+ Q_OBJECT
+public:
+ static NetworkManager* instance() {
+ if (!instance_) {
+ static NetworkManager singleton;
+ instance_ = &singleton;
+ }
+ return instance_;
+ }
+ void addWatch(QNetworkAccessManager* manager);
+ void applyProxy(const QNetworkProxy& proxy);
+ void reapplyProxy();
+
+ // retry only once
+ bool shouldRetry(const QNetworkReply::NetworkError error) {
+ if ((error == QNetworkReply::ProxyConnectionClosedError ||
+ error == QNetworkReply::ProxyConnectionRefusedError ||
+ error == QNetworkReply::ProxyNotFoundError ||
+ error == QNetworkReply::ProxyTimeoutError ||
+ error == QNetworkReply::UnknownProxyError) &&
+ should_retry_) {
+ NetworkManager::instance()->reapplyProxy();
+ should_retry_ = false;
+ return true;
+ }
+ return false;
+ }
+
+signals:
+ void proxyChanged(const QNetworkProxy& proxy);
+
+private slots:
+ void onCleanup();
+
+private:
+ std::vector<QNetworkAccessManager*> managers_;
+ NetworkManager();
+ ~NetworkManager() {}
+ NetworkManager(const NetworkManager&) /* = delete */ ;
+ bool should_retry_;
+ static NetworkManager* instance_;
+};
+
+// Check the network connection periodically, and reset the qt
+// QNetworkAccessManager if the network is reconnected.
+class NetworkStatusDetector: public QObject
+{
+ Q_OBJECT
+ SINGLETON_DEFINE(NetworkStatusDetector)
+public:
+ ~NetworkStatusDetector();
+ void start();
+ void stop();
+ void setNetworkFailure(QNetworkReply::NetworkError err);
+ void setNetworkSuccess();
+
+public slots:
+ void detect();
+
+signals:
+ void check();
+
+private:
+ NetworkStatusDetector();
+ bool shouldTreatErrorAsNetworkReset(QNetworkReply::NetworkError error);
+ QMutex network_error_mutex_;
+
+ QTimer *check_timer_;
+ bool has_network_failure_;
+};
+
+
+#endif // SEAFILE_CLIENT_NETWORK_MANAGER_H
--- /dev/null
+#if defined(Q_OS_WIN32)
+#include <shellapi.h>
+#endif
+
+#include <QDesktopServices>
+#include <QUrl>
+#include <QUrlQuery>
+#include <QVariant>
+
+extern "C" {
+#include <searpc-client.h>
+
+#include <searpc.h>
+#include <seafile/seafile.h>
+#include <seafile/seafile-object.h>
+
+}
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "ui/main-window.h"
+#include "rpc/rpc-client.h"
+#include "rpc/rpc-server.h"
+#include "rpc/local-repo.h"
+
+#include "account.h"
+#include "repo-service.h"
+#include "open-local-helper.h"
+
+namespace {
+
+const char *kSeafileProtocolScheme = "seafile";
+const char *kSeafileProtocolHostOpenFile = "openfile";
+
+
+} // namespace
+
+OpenLocalHelper* OpenLocalHelper::singleton_ = NULL;
+
+OpenLocalHelper::OpenLocalHelper()
+{
+ url_ = NULL;
+
+ QDesktopServices::setUrlHandler(kSeafileProtocolScheme, this, SLOT(openLocalFile(const QUrl&)));
+}
+
+OpenLocalHelper*
+OpenLocalHelper::instance()
+{
+ if (singleton_ == NULL) {
+ static OpenLocalHelper instance;
+ singleton_ = &instance;
+ }
+
+ return singleton_;
+}
+
+QUrl OpenLocalHelper::generateLocalFileSeafileUrl(const QString& repo_id, const Account& account, const QString& path)
+{
+ QUrl url;
+ url.setScheme(kSeafileProtocolScheme);
+ url.setHost(kSeafileProtocolHostOpenFile);
+
+ QUrlQuery url_query;
+ url_query.addQueryItem("repo_id", repo_id);
+ url_query.addQueryItem("path", path);
+ url.setQuery(url_query);
+
+ return url;
+}
+
+QUrl OpenLocalHelper::generateLocalFileWebUrl(const QString& repo_id, const Account& account, const QString& path)
+{
+ QString fixed_path = path.startsWith("/") ? path : "/" + path;
+ if (fixed_path.endsWith("/"))
+ return account.getAbsoluteUrl("/#common/lib/" + repo_id + (fixed_path == "/" ?
+ "/" : fixed_path.left(fixed_path.size() - 1)));
+ else
+ return account.getAbsoluteUrl("/lib/" + repo_id + "/file" + fixed_path);
+}
+
+bool OpenLocalHelper::openLocalFile(const QUrl &url)
+{
+ if (url.scheme() != kSeafileProtocolScheme) {
+ qWarning("[OpenLocalHelper] unknown scheme %s\n", url.scheme().toUtf8().data());
+ return false;
+ }
+
+ if (url.host() != kSeafileProtocolHostOpenFile) {
+ qWarning("[OpenLocalHelper] unknown command %s\n", url.host().toUtf8().data());
+ return false;
+ }
+
+ QUrlQuery url_query = QUrlQuery(url.query());
+ QString repo_id = url_query.queryItemValue("repo_id", QUrl::FullyDecoded);
+ QString email = url_query.queryItemValue("email", QUrl::FullyDecoded);
+ QString path = url_query.queryItemValue("path", QUrl::FullyDecoded);
+
+ if (repo_id.size() < 36) {
+ qWarning("[OpenLocalHelper] invalid repo_id %s\n", repo_id.toUtf8().data());
+ return false;
+ }
+
+ qDebug("[OpenLocalHelper] open local file: repo %s, path %s\n",
+ repo_id.toUtf8().data(), path.toUtf8().data());
+
+ RepoService::instance()->openLocalFile(repo_id, path);
+
+ return true;
+}
+
+void OpenLocalHelper::messageBox(const QString& msg)
+{
+ seafApplet->mainWindow()->showWindow();
+ seafApplet->messageBox(msg);
+}
+
+void OpenLocalHelper::handleOpenLocalFromCommandLine(const char *url)
+{
+ SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+ if (client->connect()) {
+ // An instance of seafile applet is running
+ client->sendOpenSeafileUrlCommand(QUrl::fromEncoded(url));
+ exit(0);
+ } else {
+ // No instance of seafile client running, we just record the url and
+ // let the applet start. The local file will be opened when the applet
+ // is ready.
+ setUrl(url);
+ }
+}
+
+void OpenLocalHelper::checkPendingOpenLocalRequest()
+{
+ if (!url_.isEmpty()) {
+ openLocalFile(QUrl::fromEncoded(url_));
+ setUrl(NULL);
+ }
+}
+
+bool OpenLocalHelper::activateRunningInstance()
+{
+ SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+ return client->connect() && client->sendActivateCommand();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_OPEN_LOCAL_FILE_HELPER_H
+#define SEAFILE_CLIENT_OPEN_LOCAL_FILE_HELPER_H
+
+#include <QObject>
+#include <QUrl>
+#include <QString>
+class Account;
+
+/**
+ * Helper class to handle open local file request
+ */
+class OpenLocalHelper : public QObject
+{
+ Q_OBJECT
+public:
+ static OpenLocalHelper* instance();
+
+ QUrl generateLocalFileSeafileUrl(const QString& repo_id, const Account& account, const QString& path);
+ QUrl generateLocalFileWebUrl(const QString& repo_id, const Account& account, const QString& path);
+
+ bool openLocalFile(const QUrl &url);
+
+ void setUrl(const char *url) { url_ = url; }
+
+ void handleOpenLocalFromCommandLine(const char *url);
+
+ void checkPendingOpenLocalRequest();
+
+ bool activateRunningInstance();
+
+private:
+ static OpenLocalHelper* singleton_;
+
+ OpenLocalHelper();
+
+ void messageBox(const QString& msg);
+
+ QByteArray url_;
+};
+
+
+#endif // SEAFILE_CLIENT_OPEN_LOCAL_FILE_HELPER_H
--- /dev/null
+#include <QScopedPointer>
+#include <QDir>
+
+#include "repo-service-helper.h"
+
+#include "filebrowser/data-mgr.h"
+#include "filebrowser/progress-dialog.h"
+#include "filebrowser/file-browser-requests.h"
+#include "filebrowser/tasks.h"
+#include "filebrowser/auto-update-mgr.h"
+#include "filebrowser/transfer-mgr.h"
+
+#include "ui/set-repo-password-dialog.h"
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "repo-service.h"
+
+void FileDownloadHelper::openFile(const QString& path, bool work_around_mac_auto_udpate)
+{
+ QFileInfo file(path);
+ QString file_name = file.fileName();
+ if (!file.exists()) {
+ QString msg = QObject::tr("File \"%1\" doesn't exist in \"%2\"").arg(file_name).arg(file.path());
+ seafApplet->warningBox(msg);
+ return;
+ }
+ if (!::openInNativeExtension(path) && !::showInGraphicalShell(path)) {
+ QString msg = QObject::tr("%1 couldn't find an application to open file %2").arg(getBrand()).arg(file_name);
+ seafApplet->warningBox(msg);
+ return;
+ }
+#ifdef Q_OS_MAC
+ MacImageFilesWorkAround::instance()->fileOpened(path);
+#endif
+}
+
+FileDownloadHelper::FileDownloadHelper(const Account &account, const ServerRepo &repo, const QString &path, QWidget *parent)
+ : account_(account), repo_(repo), path_(path), file_name_(QFileInfo(path).fileName()), parent_(parent), req_(NULL) {
+}
+
+FileDownloadHelper::~FileDownloadHelper()
+{
+ onCancel();
+ if (req_)
+ req_->deleteLater();
+}
+
+void FileDownloadHelper::start()
+{
+ if (req_)
+ return;
+ const QString file_name = QFileInfo(path_).fileName();
+ const QString dirent_path = ::getParentPath(path_);
+ req_ = new GetDirentsRequest(account_, repo_.id, dirent_path);
+ connect(req_, SIGNAL(success(bool, const QList<SeafDirent> &, const QString&)),
+ this, SLOT(onGetDirentsSuccess(bool, const QList<SeafDirent> &)));
+ connect(req_, SIGNAL(failed(const ApiError &)),
+ this, SLOT(onGetDirentsFailure(const ApiError &)));
+ req_->send();
+}
+
+void FileDownloadHelper::onCancel()
+{
+ if (req_)
+ disconnect(req_, 0, this, 0);
+}
+
+void FileDownloadHelper::onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents)
+{
+ Q_UNUSED(current_readonly);
+ bool found_file = false;
+ Q_FOREACH(const SeafDirent &dirent, dirents)
+ {
+ if (dirent.name == file_name_) {
+ if (dirent.isDir()) {
+ RepoService::instance()->openFolder(repo_.id, path_);
+ return;
+ }
+ downloadFile(dirent.id);
+ found_file = true;
+ break;
+ }
+ }
+ // critally important
+ if (!found_file) {
+ QString msg = QObject::tr("File \"%1\" doesn't exist in \"%2\"").arg(file_name_).arg(QFileInfo(path_).path());
+ seafApplet->warningBox(msg);
+ }
+
+}
+
+void FileDownloadHelper::downloadFile(const QString &id)
+{
+ DataManager *data_mgr = seafApplet->dataManager();
+ QString cached_file = data_mgr->getLocalCachedFile(repo_.id, path_, id);
+ if (!cached_file.isEmpty()) {
+ openFile(cached_file, false);
+ return;
+ }
+
+ // endless loop for setPasswordDialog
+ while(true) {
+ if (TransferManager::instance()->getDownloadTask(repo_.id, path_) != nullptr) {
+ return;
+ }
+ QScopedPointer<FileDownloadTask> task(data_mgr->createDownloadTask(repo_.id, path_));
+ task->setAutoDelete(false);
+ FileBrowserProgressDialog dialog(task.data(), parent_);
+ if (dialog.exec()) {
+ QString full_path =
+ data_mgr->getLocalCachedFile(repo_.id, path_, task->fileId());
+ if (!full_path.isEmpty())
+ openFile(full_path, true);
+ break;
+ }
+ // if the user canceled the task, don't bother it
+ if (task->error() == FileNetworkTask::TaskCanceled)
+ break;
+ // if the repo_sitory is encrypted and password is incorrect
+ if (repo_.encrypted && task->httpErrorCode() == 400) {
+ SetRepoPasswordDialog password_dialog(repo_, parent_);
+ if (password_dialog.exec())
+ continue;
+ // the user canceled the dialog? skip
+ break;
+ }
+ // printf ("error = %d\n", (int)task->error());
+ QString msg =
+ QObject::tr("Unable to download item \"%1\"").arg(path_);
+ seafApplet->warningBox(msg);
+ break;
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_REPO_SERVICE_HELPER_H_
+#define SEAFILE_CLIENT_REPO_SERVICE_HELPER_H_
+
+#include <QObject>
+#include <QString>
+#include <QList>
+#include <QScopedPointer>
+
+#include "account.h"
+#include "api/api-error.h"
+#include "api/server-repo.h"
+#include "filebrowser/seaf-dirent.h"
+#include "filebrowser/data-mgr.h"
+
+class GetDirentsRequest;
+class QWidget;
+
+class FileDownloadHelper : public QObject {
+ Q_OBJECT
+public:
+ static void openFile(const QString& path, bool work_around_mac_auto_udpate);
+ FileDownloadHelper(const Account &account, const ServerRepo &repo, const QString &path, QWidget *parent);
+ ~FileDownloadHelper();
+ void start();
+
+private slots:
+
+ void onCancel();
+ void onGetDirentsSuccess(bool current_readonly, const QList<SeafDirent> &dirents);
+ void onGetDirentsFailure(const ApiError &)
+ {
+ downloadFile(QString());
+ }
+
+private:
+ void downloadFile(const QString &id);
+
+ const Account account_;
+ const ServerRepo repo_;
+ const QString path_;
+ const QString file_name_;
+ QWidget *parent_;
+ GetDirentsRequest *req_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_SERVICE_HELPER_H_
--- /dev/null
+#include <unistd.h>
+#include <algorithm>
+
+#include <sqlite3.h>
+
+#include <QTimer>
+#include <QDir>
+#include <QSet>
+#include <QDesktopServices>
+#include <QThreadPool>
+
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "rpc/clone-task.h"
+#include "account-mgr.h"
+#include "api/server-repo.h"
+#include "api/requests.h"
+#include "ui/main-window.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/uninstall-helpers.h"
+
+#include "filebrowser/file-browser-manager.h"
+#include "filebrowser/data-cache.h"
+#include "filebrowser/data-mgr.h"
+
+#include "repo-service.h"
+#include "repo-service-helper.h"
+#include "open-local-helper.h"
+
+namespace {
+
+class SyncedSubfolder {
+public:
+ SyncedSubfolder() {}
+ SyncedSubfolder(const QString &repo_id, const QString &parent_repo_id,
+ const QString &parent_path)
+ : repo_id_(repo_id), parent_repo_id_(parent_repo_id),
+ parent_path_(parent_path) {}
+ SyncedSubfolder(const ServerRepo &repo, const ServerRepo &parent_repo,
+ const QString &parent_path)
+ : repo_id_(repo.id), parent_repo_id_(parent_repo.id),
+ parent_path_(parent_path) {}
+ SyncedSubfolder(const SyncedSubfolder &rhs)
+ : repo_id_(rhs.repo_id_), parent_repo_id_(rhs.parent_repo_id_),
+ parent_path_(rhs.parent_path_) {}
+
+ SyncedSubfolder& operator=(const SyncedSubfolder &rhs)
+ {
+ repo_id_ = rhs.repo_id_;
+ parent_repo_id_ = rhs.parent_repo_id_;
+ parent_path_ = rhs.parent_path_;
+ return *this;
+ }
+
+ const QString& repoId() const { return repo_id_; }
+ const QString& parentRepoId() const { return parent_repo_id_; }
+ const QString& parentPath() const { return parent_path_; }
+
+ bool isValid() const { return !repo_id_.isEmpty(); }
+
+private:
+ QString repo_id_;
+ QString parent_repo_id_;
+ QString parent_path_;
+};
+
+const int kRefreshReposInterval = 1000 * 60 * 5; // 5 min
+
+bool loadSyncedFolderCB(sqlite3_stmt *stmt, void *data)
+{
+ std::vector<SyncedSubfolder> *synced_subfolders = static_cast<std::vector<SyncedSubfolder> *>(data);
+ const char *repo_id = (const char *)sqlite3_column_text (stmt, 0);
+ const char *parent_repo_id = (const char *)sqlite3_column_text (stmt, 1);
+ const char *parent_path = (const char *)sqlite3_column_text (stmt, 2);
+ synced_subfolders->push_back(SyncedSubfolder(repo_id, parent_repo_id, parent_path));
+
+ return true;
+}
+
+// TODO: use lambda to replace this helper class if we are switching to C++11
+template<class T>
+class RepohasRepoID {
+public:
+ RepohasRepoID(const QString &repo_id) : repo_id_(repo_id) {}
+ bool operator()(const T &repo) {
+ return repo.id == repo_id_;
+ }
+
+private:
+ const QString& repo_id_;
+};
+
+class SyncedSubfolderhasRepoID {
+public:
+ SyncedSubfolderhasRepoID(const QString &repo_id) : repo_id_(repo_id) {}
+ bool operator()(const SyncedSubfolder &subfolder) {
+ return subfolder.repoId() == repo_id_;
+ }
+
+private:
+ const QString& repo_id_;
+};
+
+// don't rely on this,
+// it is used for get repo request only
+std::vector<SyncedSubfolder> synced_subfolders_;
+
+} // namespace
+
+SINGLETON_IMPL(RepoService)
+
+RepoService::RepoService(QObject *parent)
+ : QObject(parent), synced_subfolder_db_(NULL)
+{
+ refresh_timer_ = new QTimer(this);
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+ list_repo_req_ = NULL;
+ in_refresh_ = false;
+ wipe_in_progress_ = false;
+}
+
+RepoService::~RepoService()
+{
+ if (synced_subfolder_db_)
+ sqlite3_close(synced_subfolder_db_);
+}
+
+void RepoService::start()
+{
+ const char *errmsg;
+
+ if (!synced_subfolder_db_) {
+ do {
+ QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("accounts.db");
+ if (sqlite3_open (db_path.toUtf8().data(), &synced_subfolder_db_)) {
+ errmsg = sqlite3_errmsg (synced_subfolder_db_);
+ qWarning("failed to open synced subfolder database %s: %s",
+ db_path.toUtf8().data(), errmsg ? errmsg : "no error given");
+
+ sqlite3_close(synced_subfolder_db_);
+ synced_subfolder_db_ = NULL;
+ break;
+ }
+
+ // enabling foreign keys, it must be done manually from each connection
+ // and this feature is only supported from sqlite 3.6.19
+ const char *sql = "PRAGMA foreign_keys=ON;";
+ if (sqlite_query_exec (synced_subfolder_db_, sql) < 0) {
+ qWarning("sqlite version is too low to support foreign key feature\n");
+ qWarning("feature synced_sub_folder is disabled\n");
+ sqlite3_close(synced_subfolder_db_);
+ synced_subfolder_db_ = NULL;
+ break;
+ }
+
+ // create SyncedSubfolder table
+ sql = "CREATE TABLE IF NOT EXISTS SyncedSubfolder ("
+ "repo_id TEXT PRIMARY KEY, parent_repo_id TEXT NOT NULL, "
+ "url VARCHAR(24), username VARCHAR(15), "
+ "parent_path TEXT NOT NULL, "
+ "FOREIGN KEY(url, username) REFERENCES Accounts(url, username) "
+ "ON DELETE CASCADE ON UPDATE CASCADE )";
+ if (sqlite_query_exec (synced_subfolder_db_, sql) < 0) {
+ qWarning("failed to create synced subfolder table\n");
+ sqlite3_close(synced_subfolder_db_);
+ synced_subfolder_db_ = NULL;
+ }
+ } while (0);
+ }
+
+ refresh_timer_->start(kRefreshReposInterval);
+}
+
+void RepoService::stop()
+{
+ refresh_timer_->stop();
+}
+
+void RepoService::refreshLocalRepoList() {
+ // local_repos_.clear(); is called intenally
+ if (seafApplet->rpcClient()->listLocalRepos(&local_repos_) < 0) {
+ qWarning("unable to refresh local repos\n");
+ }
+}
+
+void RepoService::refresh()
+{
+ if (in_refresh_) {
+ return;
+ }
+
+ const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+ if (accounts.empty()) {
+ in_refresh_ = false;
+ return;
+ }
+
+ const Account *account = &accounts.front();
+
+ if (!account->isValid())
+ return;
+
+ in_refresh_ = true;
+
+ if (!get_repo_reqs_.empty()) {
+ for (std::list<GetRepoRequest*>::iterator pos = get_repo_reqs_.begin(); pos != get_repo_reqs_.end(); ++pos)
+ delete (*pos);
+ get_repo_reqs_.clear();
+ }
+
+ refreshLocalRepoList();
+
+ synced_subfolders_.clear();
+ if (synced_subfolder_db_) {
+
+ char *zql = sqlite3_mprintf("SELECT repo_id, parent_repo_id, parent_path FROM SyncedSubfolder "
+ "WHERE url = %Q AND username = %Q",
+ account->serverUrl.toEncoded().data(),
+ account->username.toUtf8().data());;
+ sqlite_foreach_selected_row (synced_subfolder_db_, zql,
+ loadSyncedFolderCB, &synced_subfolders_);
+ sqlite3_free(zql);
+
+ std::vector<CloneTask> tasks;
+ seafApplet->rpcClient()->getCloneTasks(&tasks);
+
+ QSet<QString> local_repos;
+ for (size_t i = 0; i < tasks.size(); ++i) {
+ local_repos.insert(tasks[i].repo_id);
+ }
+ for (size_t i = 0; i < local_repos_.size(); ++i) {
+ local_repos.insert(local_repos_[i].id);
+ }
+
+ // If the synced virtual repo no longer exists locally, remove it from
+ // applet database.
+ for (size_t i = 0; i < synced_subfolders_.size(); ++i) {
+ if (!local_repos.contains(synced_subfolders_[i].repoId())) {
+ removeSyncedSubfolder(synced_subfolders_[i].repoId());
+ }
+ }
+ }
+
+ if (list_repo_req_) {
+ list_repo_req_->deleteLater();
+ }
+
+ list_repo_req_ = new ListReposRequest(*account);
+
+ connect(list_repo_req_, SIGNAL(success(const std::vector<ServerRepo>&)),
+ this, SLOT(onRefreshSuccess(const std::vector<ServerRepo>&)));
+
+ connect(list_repo_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onRefreshFailed(const ApiError&)));
+ list_repo_req_->send();
+}
+
+void RepoService::onRefreshSuccess(const std::vector<ServerRepo>& repos)
+{
+ in_refresh_ = false;
+
+ server_repos_ = repos;
+
+ OpenLocalHelper::instance()->checkPendingOpenLocalRequest();
+
+ // if we have local repo missed in server_repos
+ // start a GetRepoRequest for it
+ for (size_t i = 0; i < synced_subfolders_.size(); ++i) {
+ bool found = false;
+ for (size_t j = 0; j < server_repos_.size(); ++j) {
+ if (synced_subfolders_[i].repoId() == server_repos_[j].id) {
+ found = true;
+ server_repos_[j].parent_repo_id = synced_subfolders_[i].parentRepoId();
+ server_repos_[j].parent_path = synced_subfolders_[i].parentPath();
+ break;
+ }
+ }
+ // create GetRepoRequest
+ if (!found)
+ startGetRequestFor(synced_subfolders_[i].repoId());
+ }
+
+ if (get_repo_reqs_.empty())
+ emit refreshSuccess(repos);
+}
+
+void RepoService::onRefreshFailed(const ApiError& error)
+{
+ in_refresh_ = false;
+
+ if (list_repo_req_->reply()->hasRawHeader("X-Seafile-Wiped")) {
+ qWarning ("current device is marked to be remote wiped\n");
+ // TODO: Remote wipe should be managed in a separate module, not here.
+ if (!wipe_in_progress_) {
+ wipe_in_progress_ = true;
+ wipeLocalFiles();
+ }
+ return;
+ }
+
+ // for the new version of seafile server
+ // we may have a 401 response whenever invalid token is used.
+ // see more: https://github.com/haiwen/seahub/commit/94dcfe338a52304f5895914ac59540b6176c679e
+ // but we only handle this error here to avoid complicate code since it is
+ // general enough.
+ // TODO move this handling to all possible cases
+ if (error.type() == ApiError::HTTP_ERROR && error.httpErrorCode() == 401) {
+ seafApplet->accountManager()->invalidateCurrentLogin();
+ return;
+ }
+
+ emit refreshFailed(error);
+}
+
+void RepoService::refresh(bool force)
+{
+ if (!force || !in_refresh_) {
+ refresh();
+ return;
+ }
+
+ // Abort the current request and send another
+ in_refresh_ = false;
+ refresh();
+}
+
+ServerRepo
+RepoService::getRepo(const QString& repo_id) const
+{
+ size_t n = server_repos_.size();
+ for (size_t i = 0; i < n; i++) {
+ const ServerRepo &repo = server_repos_[i];
+ if (repo.id == repo_id) {
+ return repo;
+ }
+ }
+
+ return ServerRepo();
+}
+
+void RepoService::openLocalFile(const QString& repo_id,
+ const QString& path_in_repo,
+ QWidget *dialog_parent)
+{
+ if (path_in_repo.endsWith("/")) {
+ openFolder(repo_id, path_in_repo.left(path_in_repo.size() - 1));
+ return;
+ }
+ qDebug("trying to open file %s in library %s", path_in_repo.toUtf8().data(), repo_id.toUtf8().data());
+
+ LocalRepo r;
+
+ seafApplet->rpcClient()->getLocalRepo(repo_id, &r);
+
+ if (r.isValid()) {
+ QString local_path = ::pathJoin(r.worktree, path_in_repo);
+
+ FileDownloadHelper::openFile(local_path, false);
+ } else {
+ ServerRepo repo = getRepo(repo_id);
+ if (!repo.isValid()) {
+ QString msg = tr("Unable to open file \"%1\" from nonexistent library \"%2\"").arg(path_in_repo).arg(repo_id);
+ seafApplet->warningBox(msg);
+ return;
+ }
+
+ const QString path = "/" + path_in_repo;
+ //TODO select the correct account
+ const Account account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ qWarning("no valid account found");
+ return;
+ }
+ FileDownloadHelper *helper =
+ new FileDownloadHelper(account, repo, path, dialog_parent);
+ helper->setParent(dialog_parent);
+ helper->start();
+ }
+}
+
+void RepoService::openFolder(const QString &repo_id,
+ const QString &path_in_repo)
+{
+ qDebug("trying to open folder %s in library %s", path_in_repo.toUtf8().data(), repo_id.toUtf8().data());
+ LocalRepo r;
+
+ seafApplet->rpcClient()->getLocalRepo(repo_id, &r);
+
+ if (r.isValid()) {
+ QString local_path = ::pathJoin(r.worktree, path_in_repo);
+
+ FileDownloadHelper::openFile(local_path, false);
+ } else {
+ QString fixed_path = path_in_repo == "." ? "/" : path_in_repo;
+ ServerRepo repo = getRepo(repo_id);
+ if (!repo.isValid()) {
+ QString msg = tr("Unable to open file \"%1\" from nonexistent library \"%2\"").arg(path_in_repo).arg(repo_id);
+ seafApplet->warningBox(msg);
+ return;
+ }
+
+ //TODO select the correct account
+ const Account account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ qWarning("no valid account found");
+ return;
+ }
+ FileBrowserManager::getInstance()->openOrActivateDialog(account, repo, fixed_path);
+ }
+}
+
+void RepoService::onGetRequestSuccess(const ServerRepo& repo)
+{
+ GetRepoRequest* req = qobject_cast<GetRepoRequest*>(sender());
+ if (!req)
+ return;
+
+ SyncedSubfolderhasRepoID subfolder_helper(repo.id);
+ std::vector<SyncedSubfolder>::iterator pos = std::find_if(synced_subfolders_.begin(), synced_subfolders_.end(), subfolder_helper);
+
+ if (pos != synced_subfolders_.end()) {
+ ServerRepo fixed_repo = repo;
+ fixed_repo.parent_path = pos->parentPath();
+ fixed_repo.parent_repo_id = pos->parentRepoId();
+ server_repos_.push_back(fixed_repo);
+ }
+
+ // delete current request
+ req->deleteLater();
+ get_repo_reqs_.pop_front();
+
+ // start the next request or mark it as success
+ if (!get_repo_reqs_.empty())
+ get_repo_reqs_.front()->send();
+ else
+ emit refreshSuccess(server_repos_);
+}
+
+void RepoService::onGetRequestFailed(const ApiError& /*error*/)
+{
+ GetRepoRequest* req = qobject_cast<GetRepoRequest*>(sender());
+ if (!req)
+ return;
+
+ // delete current request
+ req->deleteLater();
+ get_repo_reqs_.pop_front();
+
+ // start the next request or mark it as success
+ if (!get_repo_reqs_.empty())
+ get_repo_reqs_.front()->send();
+ else
+ emit refreshSuccess(server_repos_);
+}
+
+void RepoService::startGetRequestFor(const QString &repo_id)
+{
+ bool was_empty = get_repo_reqs_.empty();
+ GetRepoRequest *req = new GetRepoRequest(seafApplet->accountManager()->currentAccount(), repo_id);
+ get_repo_reqs_.push_back(req);
+ connect(req, SIGNAL(success(const ServerRepo&)), this, SLOT(onGetRequestSuccess(const ServerRepo&)));
+ connect(req, SIGNAL(failed(const ApiError&)), this, SLOT(onGetRequestFailed(const ApiError&)));
+ if (was_empty)
+ req->send();
+}
+
+void RepoService::saveSyncedSubfolder(const ServerRepo& subfolder)
+{
+ const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+ if (accounts.empty() || !subfolder.isSubfolder())
+ return;
+ const Account *account = &accounts.front();
+
+ // if we have it before
+ RepohasRepoID<ServerRepo> repo_helper(subfolder.id);
+ std::vector<ServerRepo>::iterator pos = std::find_if(server_repos_.begin(), server_repos_.end(), repo_helper);
+ if (pos == server_repos_.end()) {
+ server_repos_.push_back(subfolder);
+ } else {
+ pos->parent_path = subfolder.parent_path;
+ pos->parent_repo_id = subfolder.parent_repo_id;
+ }
+
+ if (!synced_subfolder_db_) {
+ qWarning("synced subfolder database is not available\n");
+ return;
+ }
+
+ char *zql = sqlite3_mprintf(
+ "REPLACE INTO SyncedSubfolder(repo_id, parent_repo_id, url, username, "
+ "parent_path) VALUES (%Q, %Q, %Q, %Q, %Q)",
+ subfolder.id.toUtf8().data(), subfolder.parent_repo_id.toUtf8().data(),
+ account->serverUrl.toEncoded().data(),
+ account->username.toUtf8().data(),
+ subfolder.parent_path.toUtf8().data());
+ sqlite_query_exec (synced_subfolder_db_, zql);
+ sqlite3_free(zql);
+
+ emit refreshSuccess(server_repos_);
+}
+
+void RepoService::removeSyncedSubfolder(const QString& repo_id)
+{
+ char *zql = sqlite3_mprintf("DELETE FROM SyncedSubfolder WHERE repo_id = %Q", repo_id.toUtf8().data());
+ sqlite_query_exec(synced_subfolder_db_, zql);
+ sqlite3_free(zql);
+
+ SyncedSubfolderhasRepoID subfolder_helper(repo_id);
+ synced_subfolders_.erase(std::remove_if(synced_subfolders_.begin(), synced_subfolders_.end(), subfolder_helper), synced_subfolders_.end());
+
+ RepohasRepoID<ServerRepo> repo_helper(repo_id);
+ std::vector<ServerRepo>::iterator pos = std::remove_if(server_repos_.begin(), server_repos_.end(), repo_helper);
+ if (pos != server_repos_.end() && pos->isSubfolder()) {
+ server_repos_.erase(pos, server_repos_.end());
+
+ emit refreshSuccess(server_repos_);
+ }
+}
+
+void RepoService::removeCloudFileBrowserCache()
+{
+ QList<FileCache::CacheEntry> all_files =
+ FileCache::instance()->getAllCachedFiles();
+ const Account account = seafApplet->accountManager()->currentAccount();
+ foreach (const FileCache::CacheEntry& entry, all_files) {
+ if (account.getSignature() == entry.account_sig) {
+ QString fullpath = DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+ QFileInfo fileinfo(fullpath);
+ if (entry.seafile_mtime == fileinfo.lastModified().toMSecsSinceEpoch() && entry.seafile_size == fileinfo.size()) {
+ ::unlink((const char*)(toCStr(fullpath)));
+ FileCache::instance()->cleanUnModifiedCacheItemInDatabase(entry.file_id);
+ printf ("removing unmodified cached file %s\n", toCStr(fullpath));
+ }
+ }
+ }
+}
+
+
+void WipeFilesThread::run()
+{
+ for (size_t i = 0; i < local_repos_.size(); ++i) {
+ const LocalRepo& repo = local_repos_[i];
+ qWarning ("removing all files of repo %s: %s\n",
+ toCStr(repo.name),
+ toCStr(repo.worktree));
+ if (repo.worktree.length() > 1) {
+ delete_dir_recursively(repo.worktree);
+ }
+ }
+
+ for (int i = 0; i < cached_files_.size(); i++) {
+ ::unlink(toCStr(cached_files_[i]));
+ }
+
+ emit done();
+}
+
+void RepoService::wipeLocalFiles()
+{
+ const Account& account = seafApplet->accountManager()->currentAccount();
+
+ // Collect repo worktrees
+ std::vector<LocalRepo> repos_to_wipe;
+ seafApplet->rpcClient()->listLocalRepos(&local_repos_);
+ QStringList worktrees;
+ for (size_t i = 0; i < local_repos_.size(); ++i) {
+ const LocalRepo& repo = local_repos_[i];
+
+ QString repo_server_url;
+ if (seafApplet->rpcClient()->getRepoProperty(repo.id, "server-url", &repo_server_url) < 0) {
+ continue;
+ }
+ if (QUrl(repo_server_url).host() != account.serverUrl.host()) {
+ continue;
+ }
+
+ seafApplet->rpcClient()->unsync(repo.id);
+ repos_to_wipe.push_back(repo);
+ }
+
+ // Collect files cached by cloud file browser
+ QStringList cached_files;
+ QList<FileCache::CacheEntry> all_files =
+ FileCache::instance()->getAllCachedFiles();
+ foreach (const FileCache::CacheEntry& entry, all_files) {
+ if (account.getSignature() == entry.account_sig) {
+ QString fullpath = DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+ cached_files << DataManager::getLocalCacheFilePath(entry.repo_id, entry.path);
+ }
+ }
+
+ WipeFilesThread *wiper = new WipeFilesThread(repos_to_wipe, cached_files);
+ connect(wiper, SIGNAL(done()), this, SLOT(onWiperDone()));
+
+ QThreadPool::globalInstance()->start(wiper);
+}
+
+void RepoService::onWiperDone()
+{
+ RemoteWipeReportRequest *req = new RemoteWipeReportRequest(
+ seafApplet->accountManager()->currentAccount());
+
+ connect(req,
+ SIGNAL(success()),
+ this,
+ SLOT(onRemoteWipeReportSuccess()));
+
+ connect(req,
+ SIGNAL(failed(const ApiError &)),
+ this,
+ SLOT(onRemoteWipeReportFailed(const ApiError &)));
+
+ req->send();
+}
+
+void RepoService::onRemoteWipeReportSuccess()
+{
+ wipe_in_progress_ = false;
+ RemoteWipeReportRequest* req = qobject_cast<RemoteWipeReportRequest*>(sender());
+ req->deleteLater();
+ seafApplet->accountManager()->invalidateCurrentLogin();
+}
+
+void RepoService::onRemoteWipeReportFailed(const ApiError& error)
+{
+ wipe_in_progress_ = false;
+ RemoteWipeReportRequest* req = qobject_cast<RemoteWipeReportRequest*>(sender());
+ req->deleteLater();
+ seafApplet->accountManager()->invalidateCurrentLogin();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_REPO_SERVICE_H_
+#define SEAFILE_CLIENT_REPO_SERVICE_H_
+
+#include <vector>
+#include <QObject>
+#include <QRunnable>
+
+#include "utils/singleton.h"
+#include "rpc/local-repo.h"
+#include "api/server-repo.h"
+
+class QTimer;
+
+class ApiError;
+class ListReposRequest;
+class GetRepoRequest;
+
+struct sqlite3;
+
+
+class RepoService : public QObject {
+ SINGLETON_DEFINE(RepoService)
+ Q_OBJECT
+public:
+ void start();
+ void stop();
+
+ const std::vector<ServerRepo>& serverRepos() const { return server_repos_; }
+
+ const std::vector<LocalRepo>& localRepos() const { return local_repos_; }
+
+ ServerRepo getRepo(const QString& repo_id) const;
+
+ void saveSyncedSubfolder(const ServerRepo& subfolder);
+ void removeSyncedSubfolder(const QString& repo_id);
+
+ void refreshLocalRepoList();
+
+ void refresh(bool force);
+
+ void openLocalFile(const QString& repo_id,
+ const QString& path_in_repo,
+ QWidget *dialog_parent=0);
+
+ void openRepoOnSeahub(const QString& repo_id);
+
+ void openFolder(const QString &repo_id,
+ const QString &path_in_repo);
+ void removeCloudFileBrowserCache();
+
+public slots:
+ void refresh();
+
+private slots:
+ void onRefreshSuccess(const std::vector<ServerRepo>& repos);
+ void onRefreshFailed(const ApiError& error);
+
+ void onGetRequestSuccess(const ServerRepo& repo);
+ void onGetRequestFailed(const ApiError& error);
+
+ void onWiperDone();
+
+ void onRemoteWipeReportSuccess();
+ void onRemoteWipeReportFailed(const ApiError& error);
+
+signals:
+ void refreshSuccess(const std::vector<ServerRepo>& repos);
+ void refreshFailed(const ApiError& error);
+
+private:
+ Q_DISABLE_COPY(RepoService)
+ ~RepoService();
+
+ RepoService(QObject *parent=0);
+
+ void startGetRequestFor(const QString &repo_id);
+ void wipeLocalFiles();
+
+ ListReposRequest *list_repo_req_;
+ std::list<GetRepoRequest*> get_repo_reqs_;
+ struct sqlite3 *synced_subfolder_db_;
+
+ std::vector<ServerRepo> server_repos_;
+ std::vector<LocalRepo> local_repos_;
+
+ QTimer *refresh_timer_;
+ bool in_refresh_;
+
+ bool wipe_in_progress_;
+};
+
+
+class WipeFilesThread : public QObject, public QRunnable
+{
+ Q_OBJECT
+public:
+ WipeFilesThread(const std::vector<LocalRepo>& local_repos,
+ const QStringList& cached_files)
+ : local_repos_(local_repos),
+ cached_files_(cached_files) {};
+
+ void run();
+
+signals:
+ void done();
+
+private:
+ const std::vector<LocalRepo> local_repos_;
+ const QStringList cached_files_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_SERVICE_H_
--- /dev/null
+#include <QObject>
+#include <QStringList>
+#include <glib-object.h>
+
+#include "utils/utils.h"
+#include "clone-task.h"
+#include "utils/seafile-error.h"
+
+CloneTask CloneTask::fromGObject(GObject *obj)
+{
+ CloneTask task;
+
+ char *state = NULL;
+ int error_code = 0;
+ char *repo_id = NULL;
+ char *repo_name = NULL;
+ char *worktree = NULL;
+
+ g_object_get (obj,
+ "state", &state,
+ "error", &error_code,
+ "repo_id", &repo_id,
+ "repo_name", &repo_name,
+ "worktree", &worktree,
+ NULL);
+
+ task.state = QString::fromUtf8(state);
+ task.error_code = error_code;
+ task.repo_id = QString::fromUtf8(repo_id);
+ task.repo_name = QString::fromUtf8(repo_name);
+ task.worktree = QString::fromUtf8(worktree);
+
+ task.block_done = 0;
+ task.block_total = 0;
+
+ task.checkout_done = 0;
+ task.checkout_total = 0;
+
+ g_free (state);
+ g_free (repo_id);
+ g_free (repo_name);
+ g_free (worktree);
+
+ // task.translateStateInfo();
+
+ return task;
+}
+
+QString CloneTask::calcProgress(int64_t done, int64_t total)
+{
+ if (total == 0) {
+ return QString();
+ }
+
+ int64_t percentage = done * 100 / total;
+
+ return QString().sprintf(" %lld%%", percentage);
+}
+
+void CloneTask::translateStateInfo()
+{
+ if (state == "init") {
+ state_str = QObject::tr("initializing...");
+
+ } else if (state == "check server") {
+ state_str = QObject::tr("checking server info...");
+
+ } else if (state == "fetch") {
+ if (rt_state == "fs") {
+ state_str = QObject::tr("Downloading file list...");
+ if (fs_objects_total != 0) {
+ state_str += calcProgress(fs_objects_done, fs_objects_total);
+ }
+ } else if (rt_state == "data") {
+ state_str = QObject::tr("Downloading files...");
+ if (block_total != 0) {
+ state_str += calcProgress(block_done, block_total);
+ }
+ }
+
+ } else if (state == "done") {
+ state_str = QObject::tr("Done");
+
+ } else if (state == "canceling") {
+ state_str = QObject::tr("Canceling");
+
+ } else if (state == "canceled") {
+ state_str = QObject::tr("Canceled");
+
+ } else if (state == "error") {
+ error_str = translateSyncErrorCode(error_code);
+ } else if (state == "connect") {
+ state_str = QObject::tr("connecting server...");
+
+ } else if (state == "index") {
+ state_str = QObject::tr("indexing files...");
+
+ } else if (state == "checkout") {
+ state_str = QObject::tr("Creating folder...");
+ if (checkout_total != 0) {
+ state_str += calcProgress(checkout_done, checkout_total);
+ }
+
+ } else if (state == "merge") {
+ state_str = QObject::tr("Merge file changes...");
+ }
+
+ if (state != "error" || error_str == "ok") {
+ error_str = "";
+ }
+}
+
+bool CloneTask::isCancelable() const
+{
+ QStringList list;
+ list << "init" << "connect" << "index" << "fetch" << "error";
+ return list.contains(state);
+}
+
+
+bool CloneTask::isRemovable() const
+{
+ QStringList list;
+ list << "done" << "canceled";
+ return list.contains(state);
+}
+
+bool CloneTask::isDisplayable() const
+{
+ return state != "canceled" && state != "done";
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_RPC_CLONE_TASK_H
+#define SEAFILE_CLIENT_RPC_CLONE_TASK_H
+
+#include <QString>
+#include <QMetaType>
+
+struct _GObject;
+
+class CloneTask {
+public:
+ QString repo_id;
+ QString repo_name;
+ QString worktree;
+ QString state;
+ QString rt_state;
+ QString error_str;
+ int error_code;
+
+ QString state_str;
+ qint64 block_done;
+ qint64 block_total;
+
+ int fs_objects_done;
+ int fs_objects_total;
+
+ int checkout_done;
+ int checkout_total;
+
+ static CloneTask fromGObject(_GObject *obj);
+
+ void translateStateInfo();
+
+ bool isCancelable() const;
+ bool isRemovable() const;
+ bool isDisplayable() const;
+ bool isSuccessful() const { return state == "done"; }
+
+ bool isValid() const { return !repo_id.isEmpty(); }
+
+ bool operator==(const CloneTask& rhs) const {
+ return repo_id == rhs.repo_id
+ && repo_name == rhs.repo_name
+ && worktree == rhs.worktree
+ && state_str == rhs.state_str
+ && error_code == rhs.error_code
+ && error_str == rhs.error_str;
+ }
+
+ bool operator!=(const CloneTask& rhs) const {
+ return !(*this == rhs);
+ }
+
+private:
+ QString calcProgress(int64_t done, int64_t total);
+};
+
+#endif // SEAFILE_CLIENT_RPC_CLONE_TASK_H
--- /dev/null
+#include <glib-object.h>
+#include <ui/tray-icon.h>
+
+#include "utils/utils.h"
+#include "utils/seafile-error.h"
+#include "seafile-applet.h"
+#include "local-repo.h"
+
+LocalRepo LocalRepo::fromGObject(GObject *obj)
+{
+ char *id = NULL;
+ char *name = NULL;
+ char *desc = NULL;
+ char *worktree = NULL;
+ char *relay_id = NULL;
+
+ gboolean encrypted;
+ gboolean auto_sync;
+ gboolean worktree_invalid;
+ gint64 last_sync_time;
+ int version;
+
+ g_object_get (obj,
+ "id", &id,
+ "name", &name,
+ "desc", &desc,
+ "encrypted", &encrypted,
+ "worktree", &worktree,
+ "auto-sync", &auto_sync,
+ "last-sync-time", &last_sync_time,
+ "worktree-invalid", &worktree_invalid,
+ "relay-id", &relay_id,
+ "version", &version,
+ NULL);
+
+ LocalRepo repo;
+ repo.id = QString::fromUtf8(id);
+ repo.name = QString::fromUtf8(name);
+ repo.description = QString::fromUtf8(desc);
+ repo.worktree = QString::fromUtf8(worktree);
+ repo.encrypted = encrypted;
+ repo.auto_sync = auto_sync;
+ repo.last_sync_time = last_sync_time;
+ repo.worktree_invalid = worktree_invalid;
+ repo.relay_id = relay_id;
+ repo.version = version;
+
+ g_free (id);
+ g_free (name);
+ g_free (desc);
+ g_free (worktree);
+ g_free (relay_id);
+
+ return repo;
+}
+
+void LocalRepo::setSyncInfo(const QString &state, const int error)
+{
+ // qWarning("error: %s\n", toCStr(error));
+ // qWarning("state: %s\n", toCStr(state));
+ if (error != SYNC_ERROR_ID_NO_ERROR) {
+ translateSyncError(error);
+ } else {
+ translateSyncState(state);
+ }
+}
+
+void LocalRepo::translateSyncState(const QString &status)
+{
+ if (status == "synchronized") {
+ sync_state_str = QObject::tr("synchronized");
+ sync_state = SYNC_STATE_DONE;
+
+ } else if (status == "committing") {
+ sync_state_str = QObject::tr("indexing files");
+ sync_state = SYNC_STATE_ING;
+ has_data_transfer = false;
+
+ } else if (status == "initializing") {
+ sync_state_str = QObject::tr("sync initializing");
+ sync_state = SYNC_STATE_INIT;
+
+ } else if (status == "downloading") {
+ sync_state_str = QObject::tr("downloading");
+ sync_state = SYNC_STATE_ING;
+ has_data_transfer = true;
+
+ } else if (status == "uploading") {
+ sync_state_str = QObject::tr("uploading");
+ sync_state = SYNC_STATE_ING;
+ has_data_transfer = true;
+
+ } else if (status == "merging") {
+ sync_state_str = QObject::tr("sync merging");
+ sync_state = SYNC_STATE_ING;
+ has_data_transfer = false;
+
+ } else if (status == "waiting for sync") {
+ sync_state_str = QObject::tr("waiting for sync");
+ sync_state = SYNC_STATE_WAITING;
+
+ } else if (status == "relay not connected") {
+ sync_state_str = QObject::tr("server not connected");
+ sync_state = SYNC_STATE_WAITING;
+
+ } else if (status == "relay authenticating") {
+ sync_state_str = QObject::tr("server authenticating");
+ sync_state = SYNC_STATE_WAITING;
+
+ } else if (status == "auto sync is turned off") {
+ sync_state_str = QObject::tr("auto sync is turned off");
+ sync_state = SYNC_STATE_DISABLED;
+
+ } else if (status == "cancel pending") {
+ sync_state_str = QObject::tr("sync initializing");
+ sync_state = SYNC_STATE_INIT;
+
+ } else {
+ qWarning("unknown sync status: %s\n", toCStr(status));
+ sync_state_str = QObject::tr("unknown");
+ sync_state = SYNC_STATE_UNKNOWN;
+ }
+
+ if (!auto_sync && sync_state != SYNC_STATE_ING) {
+ sync_state_str = QObject::tr("auto sync is turned off");
+ sync_state = SYNC_STATE_DISABLED;
+ return;
+ }
+}
+
+void LocalRepo::translateSyncError(const int error)
+{
+ sync_state = SYNC_STATE_ERROR;
+ sync_error_str = translateSyncErrorCode(error);
+}
+
+
+QString LocalRepo::getErrorString() const
+{
+ return sync_error_str;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_LOCAL_REPO_H
+#define SEAFILE_CLIENT_LOCAL_REPO_H
+
+#include <QString>
+#include <QIcon>
+#include <QMetaType>
+
+#include "account.h"
+#include <seafile/seafile-error.h>
+
+struct _GObject;
+
+/**
+ * Repo Information from local seaf-daemon
+ */
+class LocalRepo {
+public:
+ enum SyncState {
+ SYNC_STATE_DISABLED,
+ SYNC_STATE_WAITING,
+ SYNC_STATE_INIT,
+ SYNC_STATE_ING,
+ SYNC_STATE_DONE,
+ SYNC_STATE_ERROR,
+ SYNC_STATE_UNKNOWN,
+ };
+
+ QString id;
+ QString name;
+ QString description;
+ QString worktree;
+ bool encrypted;
+ bool auto_sync;
+ bool worktree_invalid;
+ int version;
+ QString relay_id;
+ Account account;
+
+ qint64 last_sync_time;
+ SyncState sync_state;
+ QString rt_state;
+ QString sync_state_str;
+ QString sync_error_str;
+ QString sync_error_detail;
+ int transfer_percentage;
+ int transfer_rate;
+ bool has_data_transfer;
+
+ LocalRepo()
+ : encrypted(false),
+ auto_sync(false),
+ worktree_invalid(false),
+ version(0),
+ last_sync_time(0),
+ sync_state(SYNC_STATE_DISABLED),
+ has_data_transfer(false)
+ {
+ }
+
+ static LocalRepo fromGObject(_GObject *obj);
+
+ bool operator==(const LocalRepo& rhs) const {
+ return id == rhs.id
+ && name == rhs.name
+ && description == rhs.description
+ && worktree == rhs.worktree
+ && encrypted == rhs.encrypted
+ && auto_sync == rhs.auto_sync
+ && sync_state == rhs.sync_state
+ && rt_state == rhs.rt_state
+ && sync_state_str == rhs.sync_state_str
+ && sync_error_str == rhs.sync_error_str
+ && transfer_rate == rhs.transfer_rate
+ && transfer_percentage == rhs.transfer_percentage;
+ }
+
+ bool operator!=(const LocalRepo& rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool isValid() const { return id.length() > 0; }
+
+ QString getErrorString() const;
+
+ void setSyncInfo(const QString &state, const int error = SYNC_ERROR_ID_NO_ERROR);
+
+private:
+ void translateSyncError(const int error);
+ void translateSyncState(const QString &state);
+};
+
+Q_DECLARE_METATYPE(LocalRepo)
+
+#endif // SEAFILE_CLIENT_LOCAL_REPO_H
--- /dev/null
+extern "C" {
+
+#include <searpc-client.h>
+#include <searpc-named-pipe-transport.h>
+
+#include <searpc.h>
+#include <seafile/seafile.h>
+#include <seafile/seafile-object.h>
+
+}
+
+#include <QtDebug>
+#include <QMutexLocker>
+
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "settings-mgr.h"
+
+#include "utils/utils.h"
+#include "local-repo.h"
+#include "clone-task.h"
+#include "sync-error.h"
+#include "api/commit-details.h"
+
+#if defined(Q_OS_WIN32)
+ #include "utils/utils-win.h"
+#endif
+
+#include "rpc-client.h"
+#include <seafile/seafile-error.h>
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kSeafileSockName = "\\\\.\\pipe\\seafile_";
+#else
+const char *kSeafileSockName = "seafile.sock";
+#endif
+const char *kSeafileRpcService = "seafile-rpcserver";
+const char *kSeafileThreadedRpcService = "seafile-threaded-rpcserver";
+
+QString getSeafileRpcPipePath()
+{
+#if defined(Q_OS_WIN32)
+ return utils::win::getLocalPipeName(kSeafileSockName).c_str();
+#else
+ return QDir(seafApplet->configurator()->seafileDir()).filePath(kSeafileSockName);
+#endif
+}
+
+SearpcClient *createSearpcClientWithPipeTransport(const char *rpc_service)
+{
+ SearpcNamedPipeClient *pipe_client;
+ pipe_client = searpc_create_named_pipe_client(toCStr(getSeafileRpcPipePath()));
+ int ret = searpc_named_pipe_client_connect(pipe_client);
+ SearpcClient *c = searpc_client_with_named_pipe_transport(pipe_client, rpc_service);
+ if (ret < 0) {
+ searpc_free_client_with_pipe_transport(c);
+ return nullptr;
+ }
+ return c;
+}
+
+} // namespace
+
+SeafileRpcClient::SeafileRpcClient()
+ : connected_(false),
+ seafile_rpc_client_(nullptr),
+ seafile_threaded_rpc_client_(nullptr)
+{
+}
+
+SeafileRpcClient::~SeafileRpcClient()
+{
+ if (seafile_rpc_client_) {
+ searpc_free_client_with_pipe_transport(seafile_rpc_client_);
+ seafile_rpc_client_ = nullptr;
+ }
+ if (seafile_threaded_rpc_client_) {
+ searpc_free_client_with_pipe_transport(seafile_threaded_rpc_client_);
+ seafile_threaded_rpc_client_ = nullptr;
+ }
+}
+
+bool SeafileRpcClient::connectDaemon(bool exit_on_error)
+{
+ int retry = 0;
+ while (true) {
+ seafile_rpc_client_ = createSearpcClientWithPipeTransport(kSeafileRpcService);
+ if (!seafile_rpc_client_) {
+ if (retry++ > 20) {
+ if (exit_on_error) {
+ seafApplet->errorAndExit(tr("internal error: failed to connect to daemon"));
+ }
+ return false;
+ } else {
+ g_usleep(500000);
+ }
+ } else {
+ // Create the searpc client for threaded rpc calls
+ seafile_threaded_rpc_client_ = createSearpcClientWithPipeTransport(kSeafileThreadedRpcService);
+ if (!seafile_threaded_rpc_client_) {
+ searpc_free_client_with_pipe_transport(seafile_rpc_client_);
+ seafile_rpc_client_ = nullptr;
+ continue;
+ }
+ break;
+ }
+ }
+
+ connected_ = true;
+ qWarning("[Rpc Client] connected to daemon");
+ return true;
+}
+
+int SeafileRpcClient::listLocalRepos(std::vector<LocalRepo> *result)
+{
+ GError *error = NULL;
+ GList *repos = seafile_get_repo_list(seafile_rpc_client_, 0, 0, &error);
+ if (error != NULL) {
+ qWarning("failed to get repo list: %s\n", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ result->clear();
+ for (GList *ptr = repos; ptr; ptr = ptr->next) {
+ result->push_back(LocalRepo::fromGObject((GObject*)ptr->data));
+ }
+
+ g_list_foreach (repos, (GFunc)g_object_unref, NULL);
+ g_list_free (repos);
+
+ return 0;
+}
+
+int SeafileRpcClient::setAutoSync(bool autoSync)
+{
+ GError *error = NULL;
+ int ret;
+ if (autoSync) {
+ ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_enable_auto_sync",
+ &error, 0);
+ } else {
+ ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_disable_auto_sync",
+ &error, 0);
+ }
+
+ if (error) {
+ qWarning("failed to set auto_sync: %s\n", error->message);
+ g_error_free(error);
+ }
+
+ return ret;
+}
+
+int SeafileRpcClient::downloadRepo(const QString& id,
+ int repo_version, const QString& name,
+ const QString& wt, const QString& token,
+ const QString& passwd, const QString& magic,
+ const QString& email, const QString& random_key,
+ int enc_version, const QString& more_info,
+ QString *error_ret)
+{
+ GError *error = NULL;
+ char *ret = searpc_client_call__string(
+ seafile_rpc_client_,
+ "seafile_download",
+ &error, 11,
+ "string", toCStr(id),
+ "int", repo_version,
+ "string", toCStr(name),
+ "string", toCStr(wt),
+ "string", toCStr(token),
+ "string", toCStr(passwd),
+ "string", toCStr(magic),
+ "string", toCStr(email),
+ "string", toCStr(random_key),
+ "int", enc_version,
+ "string", toCStr(more_info));
+
+ if (error != NULL) {
+ if (error_ret) {
+ *error_ret = error->message;
+ }
+ g_error_free(error);
+ return -1;
+ }
+
+ g_free(ret);
+ return 0;
+}
+
+int SeafileRpcClient::cloneRepo(const QString& id,
+ int repo_version, const QString &name,
+ const QString &wt, const QString &token,
+ const QString &passwd, const QString &magic,
+ const QString &email, const QString& random_key,
+ int enc_version, const QString& more_info,
+ QString *error_ret)
+{
+ GError *error = NULL;
+ char *ret = searpc_client_call__string(
+ seafile_rpc_client_,
+ "seafile_clone",
+ &error, 11,
+ "string", toCStr(id),
+ "int", repo_version,
+ "string", toCStr(name),
+ "string", toCStr(wt),
+ "string", toCStr(token),
+ "string", toCStr(passwd),
+ "string", toCStr(magic),
+ "string", toCStr(email),
+ "string", toCStr(random_key),
+ "int", enc_version,
+ "string", toCStr(more_info));
+
+ if (error != NULL) {
+ if (error_ret) {
+ // copy string
+ *error_ret = error->message;
+ }
+ g_error_free(error);
+ return -1;
+ }
+
+ g_free(ret);
+ return 0;
+}
+
+int SeafileRpcClient::getLocalRepo(const QString& repo_id, LocalRepo *repo)
+{
+ GError *error = NULL;
+ GObject *obj = searpc_client_call__object(
+ seafile_rpc_client_,
+ "seafile_get_repo",
+ SEAFILE_TYPE_REPO,
+ &error, 1,
+ "string", toCStr(repo_id));
+
+ if (error != NULL) {
+ g_error_free(error);
+ return -1;
+ }
+
+ if (obj == NULL) {
+ return -1;
+ }
+
+ *repo = LocalRepo::fromGObject(obj);
+ g_object_unref(obj);
+
+ getSyncStatus(*repo);
+ return 0;
+}
+
+int SeafileRpcClient::seafileGetConfig(const QString &key,
+ QString *value)
+{
+ GError *error = NULL;
+ char *ret = searpc_client_call__string (seafile_rpc_client_,
+ "seafile_get_config", &error,
+ 1, "string", toCStr(key));
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+ *value = QString::fromUtf8(ret);
+
+ g_free (ret);
+ return 0;
+}
+
+int SeafileRpcClient::seafileGetConfigInt(const QString &key,
+ int *value)
+{
+ GError *error = NULL;
+ *value = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_get_config_int", &error,
+ 1, "string", toCStr(key));
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+ return 0;
+}
+
+int SeafileRpcClient::seafileSetConfig(const QString &key, const QString &value)
+{
+ // printf ("set config: %s = %s\n", toCStr(key), toCStr(value));
+ GError *error = NULL;
+ searpc_client_call__int (seafile_rpc_client_,
+ "seafile_set_config", &error,
+ 2, "string", toCStr(key),
+ "string", toCStr(value));
+ if (error) {
+ qWarning("Unable to set config value %s", key.toUtf8().data());
+ g_error_free(error);
+ return -1;
+ }
+ return 0;
+}
+
+int SeafileRpcClient::setUploadRateLimit(int limit)
+{
+ return setRateLimit(UPLOAD, limit);
+}
+
+int SeafileRpcClient::setDownloadRateLimit(int limit)
+{
+ return setRateLimit(DOWNLOAD, limit);
+}
+
+int SeafileRpcClient::setRateLimit(Direction direction, int limit)
+{
+ GError *error = NULL;
+ const char *rpc = direction == UPLOAD ? "seafile_set_upload_rate_limit"
+ : "seafile_set_download_rate_limit";
+ searpc_client_call__int (seafile_rpc_client_,
+ rpc, &error,
+ 1, "int", limit);
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+ return 0;
+}
+
+int SeafileRpcClient::seafileSetConfigInt(const QString &key, int value)
+{
+ // printf ("set config: %s = %d\n", toCStr(key), value);
+ GError *error = NULL;
+ searpc_client_call__int (seafile_rpc_client_,
+ "seafile_set_config_int", &error,
+ 2, "string", toCStr(key),
+ "int", value);
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+ return 0;
+}
+
+bool SeafileRpcClient::hasLocalRepo(const QString& repo_id)
+{
+ LocalRepo repo;
+ if (getLocalRepo(repo_id, &repo) < 0) {
+ return false;
+ }
+
+ return true;
+}
+
+void SeafileRpcClient::getSyncStatus(LocalRepo &repo)
+{
+ if (repo.worktree_invalid) {
+ qWarning("get a invalid worktree when getting sync status");
+ return;
+ }
+
+ GError *error = NULL;
+ SeafileSyncTask *task = (SeafileSyncTask *)
+ searpc_client_call__object (seafile_rpc_client_,
+ "seafile_get_repo_sync_task",
+ SEAFILE_TYPE_SYNC_TASK,
+ &error, 1,
+ "string", toCStr(repo.id));
+ if (error) {
+ repo.setSyncInfo("unknown");
+ g_error_free(error);
+ return;
+ }
+
+ if (!task) {
+ repo.setSyncInfo("waiting for sync");
+ return;
+ }
+
+ char *state = NULL;
+ int err = SYNC_ERROR_ID_NO_ERROR;
+ g_object_get(task, "state", &state, "error", &err, NULL);
+
+ repo.setSyncInfo(state, err);
+
+ if (repo.sync_state == LocalRepo::SYNC_STATE_ING) {
+ getRepoTransferInfo(repo.id, &repo.transfer_rate, &repo.transfer_percentage, &repo.rt_state);
+ }
+
+ // When uploading fs objects, we show it as "uploading files list" and don't
+ // show the current precentage
+ if (QString(state) == "uploading" && repo.rt_state == "fs") {
+ repo.sync_state_str = QObject::tr("uploading file list");
+ repo.has_data_transfer = false;
+ }
+
+ g_free (state);
+ g_object_unref(task);
+}
+
+int SeafileRpcClient::getCloneTasks(std::vector<CloneTask> *tasks)
+{
+ GError *error = NULL;
+ GList *objlist = searpc_client_call__objlist(
+ seafile_rpc_client_,
+ "seafile_get_clone_tasks",
+ SEAFILE_TYPE_CLONE_TASK,
+ &error, 0);
+
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+
+ for (GList *ptr = objlist; ptr; ptr = ptr->next) {
+ CloneTask task = CloneTask::fromGObject((GObject *)ptr->data);
+
+ if (task.state == "fetch") {
+ getTransferDetail(&task);
+ }
+ task.translateStateInfo();
+ tasks->push_back(task);
+ }
+
+ g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+ g_list_free (objlist);
+
+ return 0;
+}
+
+void SeafileRpcClient::getTransferDetail(CloneTask* task)
+{
+ GError *error = NULL;
+ GObject *obj = searpc_client_call__object(
+ seafile_rpc_client_,
+ "seafile_find_transfer_task",
+ SEAFILE_TYPE_TASK,
+ &error, 1,
+ "string", toCStr(task->repo_id));
+
+ if (error != NULL) {
+ g_error_free(error);
+ return;
+ }
+
+ if (obj == NULL) {
+ return;
+ }
+
+ if (task->state == "fetch") {
+ char *rt_state = NULL;
+ g_object_get (obj, "rt_state", &rt_state, NULL);
+ task->rt_state = rt_state;
+ g_free (rt_state);
+
+ if (task->rt_state == "data") {
+ qint64 block_done = 0;
+ qint64 block_total = 0;
+
+ g_object_get (obj,
+ "block_done", &block_done,
+ "block_total", &block_total,
+ NULL);
+
+ task->block_done = block_done;
+ task->block_total = block_total;
+ } else if (task->rt_state == "fs") {
+ int fs_objects_done = 0;
+ int fs_objects_total = 0;
+
+ g_object_get (obj,
+ "fs_objects_done", &fs_objects_done,
+ "fs_objects_total", &fs_objects_total,
+ NULL);
+
+ task->fs_objects_done = fs_objects_done;
+ task->fs_objects_total = fs_objects_total;
+ }
+ }
+
+ g_object_unref (obj);
+}
+
+int SeafileRpcClient::cancelCloneTask(const QString& repo_id, QString *err)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_cancel_clone_task",
+ &error, 1,
+ "string", toCStr(repo_id));
+
+ if (ret < 0) {
+ if (err) {
+ *err = error ? error->message : tr("Unknown error");
+ }
+ if (error) {
+ g_error_free(error);
+ }
+ }
+
+ return ret;
+}
+
+int SeafileRpcClient::removeCloneTask(const QString& repo_id, QString *err)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_remove_clone_task",
+ &error, 1,
+ "string", toCStr(repo_id));
+
+ if (ret < 0) {
+ if (err) {
+ *err = error ? error->message : tr("Unknown error");
+ }
+ if (error) {
+ g_error_free(error);
+ }
+ }
+
+ return ret;
+}
+
+int SeafileRpcClient::getCloneTasksCount(int *count)
+{
+ GError *error = NULL;
+ GList *objlist = searpc_client_call__objlist(
+ seafile_rpc_client_,
+ "seafile_get_clone_tasks",
+ SEAFILE_TYPE_CLONE_TASK,
+ &error, 0);
+
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+
+ if (count) {
+ *count = g_list_length(objlist);
+ }
+
+ g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+ g_list_free (objlist);
+
+ return 0;
+}
+
+int SeafileRpcClient::unsyncReposByAccount(const QUrl& server_url,
+ const QString& email,
+ QString *err)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_unsync_repos_by_account",
+ &error, 2,
+ "string", toCStr(server_url.toString()),
+ "string", toCStr(email));
+
+ if (ret < 0 && err) {
+ if (error) {
+ *err = QString::fromUtf8(error->message);
+ g_error_free(error);
+ } else {
+ *err = tr("Unknown error");
+ }
+ }
+
+ return ret;
+}
+
+int SeafileRpcClient::getDownloadRate(int *rate)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_get_download_rate",
+ &error, 0);
+
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+
+ *rate = ret;
+ return 0;
+}
+
+int SeafileRpcClient::getUploadRate(int *rate)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_get_upload_rate",
+ &error, 0);
+
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+
+ *rate = ret;
+ return 0;
+}
+
+
+void SeafileRpcClient::setRepoAutoSync(const QString& repo_id, bool auto_sync)
+{
+ GError *error = NULL;
+ searpc_client_call__int(seafile_rpc_client_,
+ "seafile_set_repo_property",
+ &error, 3,
+ "string", toCStr(repo_id),
+ "string", "auto-sync",
+ "string", auto_sync ? "true" : "false");
+ if (error) {
+ g_error_free(error);
+ }
+}
+
+int SeafileRpcClient::unsync(const QString& repo_id)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int(seafile_rpc_client_,
+ "seafile_destroy_repo",
+ &error, 1,
+ "string", toCStr(repo_id));
+ if (error) {
+ g_error_free(error);
+ }
+
+ return ret;
+}
+
+int SeafileRpcClient::getRepoTransferInfo(const QString& repo_id, int *rate, int *percent, QString *rt_state)
+{
+ GError *error = NULL;
+ GObject *task = searpc_client_call__object (seafile_rpc_client_,
+ "seafile_find_transfer_task",
+ SEAFILE_TYPE_TASK,
+ &error, 1,
+ "string", toCStr(repo_id));
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+
+ if (!task) {
+ return -1;
+ }
+
+ int64_t finished = 0;
+ int64_t total = 0;
+ char *rt = nullptr;
+ g_object_get (task,
+ "rate", rate,
+ "block_total", &total,
+ "block_done", &finished,
+ "rt_state", &rt,
+ NULL);
+
+ if (total == 0) {
+ *percent = 0;
+ } else {
+ *percent = (int)(100 * finished / total);
+ }
+
+ if (rt) {
+ if (rt_state) {
+ *rt_state = rt;
+ }
+ g_free(rt);
+ }
+
+ g_object_unref(task);
+
+ return 0;
+}
+
+void SeafileRpcClient::syncRepoImmediately(const QString& repo_id)
+{
+ searpc_client_call__int (seafile_rpc_client_,
+ "seafile_sync", NULL,
+ 2,
+ "string", toCStr(repo_id),
+ "string", NULL);
+}
+
+int SeafileRpcClient::checkPathForClone(const QString& path, QString *err_msg)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_check_path_for_clone", &error,
+ 1, "string", toCStr(path));
+
+ if (ret == 0) {
+ return 0;
+ }
+
+ if (err_msg) {
+ *err_msg = QString::fromUtf8(error->message);
+ }
+
+ g_error_free(error);
+ return -1;
+}
+
+QString SeafileRpcClient::getCcnetPeerId()
+{
+ // TODO: Get the device id now that ccnet is removed.
+ return "";
+}
+
+int SeafileRpcClient::updateReposServerHost(const QUrl& old_server_url,
+ const QString& new_host,
+ const QString& new_server_url,
+ QString *err)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_update_repos_server_host",
+ &error, 3,
+ "string", toCStr(old_server_url.toString()),
+ "string", toCStr(new_host),
+ "string", toCStr(new_server_url));
+
+ if (ret < 0) {
+ if (error) {
+ *err = QString::fromUtf8(error->message);
+ g_error_free(error);
+ } else {
+ *err = tr("Unknown error");
+ }
+ }
+
+ return ret;
+}
+
+int SeafileRpcClient::getRepoProperty(const QString &repo_id,
+ const QString& name,
+ QString *value)
+{
+ GError *error = NULL;
+ char *ret = searpc_client_call__string (
+ seafile_rpc_client_,
+ "seafile_get_repo_property",
+ &error, 2,
+ "string", toCStr(repo_id),
+ "string", toCStr(name)
+ );
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+ *value = QString::fromUtf8(ret);
+
+ g_free(ret);
+ return 0;
+}
+
+int SeafileRpcClient::setRepoProperty(const QString &repo_id,
+ const QString& name,
+ const QString& value)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (
+ seafile_rpc_client_,
+ "seafile_set_repo_property",
+ &error, 3,
+ "string", toCStr(repo_id),
+ "string", toCStr(name),
+ "string", toCStr(value)
+ );
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+ return ret;
+}
+
+int SeafileRpcClient::removeSyncTokensByAccount(const QUrl& server_url,
+ const QString& email,
+ QString *err)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (seafile_rpc_client_,
+ "seafile_remove_repo_tokens_by_account",
+ &error, 2,
+ "string", toCStr(server_url.toString()),
+ "string", toCStr(email));
+
+ if (ret < 0 && err) {
+ if (error) {
+ *err = QString::fromUtf8(error->message);
+ g_error_free(error);
+ } else {
+ *err = tr("Unknown error");
+ }
+ }
+
+ return ret;
+}
+
+int SeafileRpcClient::setRepoToken(const QString &repo_id,
+ const QString& token)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (
+ seafile_rpc_client_,
+ "seafile_set_repo_token",
+ &error, 2,
+ "string", toCStr(repo_id),
+ "string", toCStr(token)
+ );
+ if (error) {
+ g_error_free(error);
+ return -1;
+ }
+ return ret;
+}
+
+int SeafileRpcClient::getRepoFileStatus(const QString& repo_id,
+ const QString& path_in_repo,
+ bool isdir,
+ QString *status)
+{
+ GError *error = NULL;
+ char *ret = searpc_client_call__string (
+ seafile_rpc_client_,
+ "seafile_get_path_sync_status",
+ &error, 3,
+ "string", toCStr(repo_id),
+ "string", toCStr(path_in_repo),
+ "int", isdir ? 1 : 0);
+ if (error) {
+ qWarning("failed to get path status: %s\n", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ *status = ret;
+
+ g_free (ret);
+ return 0;
+}
+
+int SeafileRpcClient::markFileLockState(const QString &repo_id,
+ const QString &path_in_repo,
+ bool lock)
+{
+ GError *error = NULL;
+ char *ret = searpc_client_call__string (
+ seafile_rpc_client_,
+ lock ? "seafile_mark_file_locked" : "seafile_mark_file_unlocked",
+ &error, 2,
+ "string", toCStr(repo_id),
+ "string", toCStr(path_in_repo));
+ if (error) {
+ qWarning("failed to mark file lock state: %s\n", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ g_free (ret);
+ return 0;
+}
+
+int SeafileRpcClient::generateMagicAndRandomKey(int enc_version,
+ const QString &repo_id,
+ const QString &passwd,
+ QString *magic,
+ QString *random_key,
+ QString *salt)
+{
+ GError *error = NULL;
+ GObject *obj = searpc_client_call__object (
+ seafile_rpc_client_,
+ "seafile_generate_magic_and_random_key",
+ SEAFILE_TYPE_ENCRYPTION_INFO,
+ &error, 3,
+ "int", enc_version,
+ "string", toCStr(repo_id),
+ "string", toCStr(passwd));
+ if (error) {
+ qWarning("failed to generate magic and random_key : %s\n", error->message);
+ g_error_free(error);
+ return -1;
+ }
+
+ char *c_magic = NULL;
+ char *c_random_key = NULL;
+ char *c_salt = NULL;
+ if (enc_version == 3) {
+ g_object_get (obj,
+ "magic", &c_magic,
+ "random_key", &c_random_key,
+ "salt", &c_salt,
+ NULL);
+ *salt = QString(c_salt);
+ g_free(c_salt);
+ } else {
+ g_object_get (obj,
+ "magic", &c_magic,
+ "random_key", &c_random_key,
+ NULL);
+ }
+
+ *magic = QString(c_magic);
+ *random_key = QString(c_random_key);
+
+ g_object_unref (obj);
+ g_free (c_magic);
+ g_free (c_random_key);
+ return 0;
+}
+
+bool SeafileRpcClient::setServerProperty(const QString &url,
+ const QString &key,
+ const QString &value)
+{
+ // printf("set server config: %s %s = %s\n", toCStr(url), toCStr(key),
+ // toCStr(value));
+ GError *error = NULL;
+ searpc_client_call__int(seafile_rpc_client_, "seafile_set_server_property",
+ &error, 3, "string", toCStr(url), "string",
+ toCStr(key), "string", toCStr(value));
+ if (error) {
+ qWarning("Unable to set server property %s %s", toCStr(url),
+ toCStr(key));
+ g_error_free(error);
+ return false;
+ }
+ return true;
+}
+
+bool SeafileRpcClient::getCommitDiff(const QString& repo_id,
+ const QString& commit_id,
+ const QString& previous_commit_id,
+ CommitDetails *details)
+{
+ QMutexLocker locker(&threaded_rpc_mutex_);
+
+ GError *error = NULL;
+ GList *objlist = searpc_client_call__objlist(
+ seafile_threaded_rpc_client_,
+ "seafile_diff",
+ SEAFILE_TYPE_DIFF_ENTRY,
+ &error, 4,
+ "string", toCStr(repo_id),
+ "string", toCStr(commit_id),
+ "string", toCStr(previous_commit_id),
+ "int", 1);
+
+ if (error) {
+ qWarning("failed to get changes in commit %.7s of repo %.7s", toCStr(commit_id), toCStr(repo_id));
+ g_error_free(error);
+ return false;
+ }
+
+ *details = CommitDetails::fromObjList(objlist);
+
+ g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+ g_list_free (objlist);
+ return true;
+}
+
+bool SeafileRpcClient::getSyncErrors(std::vector<SyncError> *errors, int offset, int limit)
+{
+ GError *error = NULL;
+ GList *objlist = searpc_client_call__objlist(
+ seafile_rpc_client_,
+ "seafile_get_file_sync_errors",
+ SEAFILE_TYPE_FILE_SYNC_ERROR,
+ &error, 2, "int", offset, "int", limit);
+
+
+ for (GList *ptr = objlist; ptr; ptr = ptr->next) {
+ SyncError error = SyncError::fromGObject((GObject *)ptr->data);
+ errors->push_back(error);
+ }
+
+ g_list_foreach (objlist, (GFunc)g_object_unref, NULL);
+ g_list_free (objlist);
+
+ return true;
+}
+
+bool SeafileRpcClient::getSyncNotification(json_t **ret_obj)
+{
+ GError *error = NULL;
+ json_t *ret = searpc_client_call__json (
+ seafile_rpc_client_,
+ "seafile_get_sync_notification",
+ &error, 0);
+ if (error) {
+ qWarning("failed to get sync notification: %s\n",
+ error->message ? error->message : "");
+ g_error_free(error);
+ return false;
+ }
+
+ if (!ret) {
+ // No pending notifications.
+ return false;
+ }
+
+ *ret_obj = ret;
+
+ return true;
+}
+
+bool SeafileRpcClient::deleteFileAsyncErrorById(int id)
+{
+ GError *error = NULL;
+ int ret = searpc_client_call__int (
+ seafile_rpc_client_,
+ "seafile_del_file_sync_error_by_id",
+ &error, 1,
+ "int", id
+ );
+ if (error) {
+ g_error_free(error);
+ return false;
+ }
+ return true;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_RPC_CLIENT_H
+#define SEAFILE_CLIENT_RPC_CLIENT_H
+
+#include <vector>
+
+#include <QObject>
+#include <QMutex>
+
+extern "C" {
+
+struct _GList;
+// Can't forward-declare type SearpcClient here because it is an anonymous typedef struct
+#include <searpc-client.h>
+
+}
+
+// Here we can't forward-declare type json_t because it is an anonymous typedef
+// struct, and unlike libsearpc we have no way to rewrite its definition to give
+// it a name.
+#include <jansson.h>
+
+class LocalRepo;
+class CloneTask;
+class SyncError;
+class CommitDetails;
+
+class SeafileRpcClient : public QObject {
+ Q_OBJECT
+
+public:
+ SeafileRpcClient();
+ ~SeafileRpcClient();
+ bool tryConnectDaemon() { return connectDaemon(false); }
+ bool connectDaemon(bool exit_on_error = true);
+ bool isConnected() const { return connected_; }
+
+ int listLocalRepos(std::vector<LocalRepo> *repos);
+ int getLocalRepo(const QString& repo_id, LocalRepo *repo);
+ int setAutoSync(const bool autoSync);
+ int downloadRepo(const QString& id,
+ int repo_version, const QString& name,
+ const QString& wt, const QString& token,
+ const QString& passwd, const QString& magic,
+ const QString& email, const QString& random_key,
+ int enc_version, const QString& more_info,
+ QString *error);
+
+ int cloneRepo(const QString& id,
+ int repo_version, const QString& name,
+ const QString& wt, const QString& token,
+ const QString& passwd, const QString& magic,
+ const QString& email, const QString& random_key,
+ int enc_version, const QString& more_info,
+ QString *error);
+
+ int seafileGetConfig(const QString& key, QString *value);
+ int seafileGetConfigInt(const QString& key, int *value);
+ int seafileSetConfig(const QString& key, const QString& value);
+ int seafileSetConfigInt(const QString& key, int value);
+
+ void getSyncStatus(LocalRepo &repo);
+ int getCloneTasks(std::vector<CloneTask> *tasks);
+ int getCloneTasksCount(int *count);
+
+ int cancelCloneTask(const QString& repo_id, QString *error);
+ int removeCloneTask(const QString& repo_id, QString *error);
+
+ int unsyncReposByAccount(const QUrl& server_url, const QString& email, QString *err);
+ int removeSyncTokensByAccount(const QUrl& server_url, const QString& email, QString *error);
+ int getUploadRate(int *rate);
+ int getDownloadRate(int *rate);
+
+ int getRepoTransferInfo(const QString& repo_id, int *rate, int *percent, QString* rt_state=nullptr);
+
+ void setRepoAutoSync(const QString& repo_id, bool auto_sync);
+ int unsync(const QString& repo_id);
+
+ int setUploadRateLimit(int limit);
+ int setDownloadRateLimit(int limit);
+
+ void syncRepoImmediately(const QString& repo_id);
+
+ int checkPathForClone(const QString& path, QString* err_msg);
+
+ // Helper functions
+ bool hasLocalRepo(const QString& repo_id);
+ int getServers(_GList** servers);
+
+ QString getCcnetPeerId();
+
+ int updateReposServerHost(const QUrl& old_server_url,
+ const QString& new_host,
+ const QString& new_server_url,
+ QString *err);
+
+ int getRepoProperty(const QString& repo_id,
+ const QString& name,
+ QString *value);
+
+ int setRepoProperty(const QString& repo_id,
+ const QString& name,
+ const QString& value);
+
+ int setRepoToken(const QString &repo_id,
+ const QString& token);
+
+ int getRepoFileStatus(const QString& repo_id,
+ const QString& path_in_repo,
+ bool isdir,
+ QString *status);
+
+ int markFileLockState(const QString& repo_id,
+ const QString& path_in_repo,
+ bool lock);
+
+ int generateMagicAndRandomKey(int enc_version,
+ const QString& repo_id,
+ const QString& passwd,
+ QString *magic,
+ QString *random_key,
+ QString *salt);
+
+ bool setServerProperty(const QString &url,
+ const QString &key,
+ const QString &value);
+
+ // Read the commit diff from the daemon. Note this rpc may block for a
+ // while.
+ bool getCommitDiff(const QString& repo_id,
+ const QString& commit_id,
+ const QString& previous_commit_id,
+ CommitDetails *details);
+
+ bool getSyncErrors(std::vector<SyncError> *errors, int offset=0, int limit=10);
+
+ bool getSyncNotification(json_t **ret);
+
+ bool deleteFileAsyncErrorById(int id);
+
+private:
+ Q_DISABLE_COPY(SeafileRpcClient)
+
+ void getTransferDetail(CloneTask* task);
+
+ enum Direction {
+ DOWNLOAD = 0,
+ UPLOAD
+ };
+ int setRateLimit(Direction, int limit);
+
+ bool connected_;
+
+ QMutex threaded_rpc_mutex_;
+
+ SearpcClient *seafile_rpc_client_;
+ SearpcClient *seafile_threaded_rpc_client_;
+};
+
+#endif
--- /dev/null
+extern "C" {
+
+#include <searpc.h>
+#include <searpc-client.h>
+#include <searpc-server.h>
+#include <searpc-named-pipe-transport.h>
+
+#include "searpc-signature.h"
+#include "searpc-marshal.h"
+
+}
+
+#include <QCoreApplication>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "ui/main-window.h"
+#include "open-local-helper.h"
+
+#if defined(Q_OS_WIN32)
+ #include "utils/utils-win.h"
+#endif
+
+#include "rpc-server.h"
+
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kSeafileAppletSockName = "\\\\.\\pipe\\seafile_client_";
+#else
+const char *kSeafileAppletSockName = "seafile_client.sock";
+#endif
+const char *kSeafileAppletRpcService = "seafile-client-rpcserver";
+
+QString getAppletRpcPipePath()
+{
+#if defined(Q_OS_WIN32)
+ return utils::win::getLocalPipeName(kSeafileAppletSockName).c_str();
+#else
+ seafApplet->configurator()->checkInit();
+ return QDir(seafApplet->configurator()->seafileDir()).filePath(kSeafileAppletSockName);
+#endif
+}
+
+char *
+handle_ping_command (GError **error)
+{
+ return strdup("pong");
+}
+
+int
+handle_activate_command (GError **error)
+{
+ qWarning("[rpc server] Got an activate command");
+ RpcServerProxy::instance()->proxyActivateCommand();
+ return 0;
+}
+
+int
+handle_exit_command (GError **error)
+{
+ qWarning("[rpc server] Got a quit command. Quit now.");
+ RpcServerProxy::instance()->proxyExitCommand();
+ return 0;
+}
+
+int
+handle_open_seafile_url_command (const char *url, GError **error)
+{
+ qWarning("[rpc server] opening seafile url %s", url);
+ RpcServerProxy::instance()->proxyOpenSeafileUrlCommand(QUrl::fromEncoded(url));
+ return 0;
+}
+
+void register_rpc_service ()
+{
+ searpc_server_init ((RegisterMarshalFunc)register_marshals);
+
+ searpc_create_service (kSeafileAppletRpcService);
+
+ searpc_server_register_function (kSeafileAppletRpcService,
+ (void *)handle_ping_command,
+ "ping",
+ searpc_signature_string__void());
+
+ searpc_server_register_function (kSeafileAppletRpcService,
+ (void *)handle_activate_command,
+ "activate",
+ searpc_signature_int__void());
+
+ searpc_server_register_function (kSeafileAppletRpcService,
+ (void *)handle_exit_command,
+ "exit",
+ searpc_signature_int__void());
+
+ searpc_server_register_function (kSeafileAppletRpcService,
+ (void *)handle_open_seafile_url_command,
+ "open_seafile_url",
+ searpc_signature_int__string());
+}
+
+
+SearpcClient *createSearpcClientWithPipeTransport(const char *rpc_service)
+{
+ SearpcNamedPipeClient *pipe_client;
+ pipe_client = searpc_create_named_pipe_client(toCStr(getAppletRpcPipePath()));
+ int ret = searpc_named_pipe_client_connect(pipe_client);
+ SearpcClient *c = searpc_client_with_named_pipe_transport(pipe_client, rpc_service);
+ if (ret < 0) {
+ searpc_free_client_with_pipe_transport(c);
+ return nullptr;
+ }
+ return c;
+}
+
+class AppletRpcClient : public SeafileAppletRpcServer::Client {
+public:
+ bool connect() {
+ seafile_rpc_client_ = createSearpcClientWithPipeTransport(kSeafileAppletRpcService);
+ if (!seafile_rpc_client_) {
+ return false;
+ }
+ return true;
+ }
+ bool sendPingCommand(QString* resp) {
+ GError *error = NULL;
+ char *ret = searpc_client_call__string (
+ seafile_rpc_client_,
+ "ping",
+ &error, 0);
+ if (error) {
+ g_error_free(error);
+ return false;
+ }
+ if (!ret) {
+ return false;
+ }
+ *resp = ret;
+ return true;
+ }
+
+ bool sendActivateCommand() {
+ GError *error = NULL;
+ int ret = searpc_client_call__int (
+ seafile_rpc_client_,
+ "activate",
+ &error, 0);
+ if (error) {
+ g_error_free(error);
+ return false;
+ }
+ if (ret != 0) {
+ return false;
+ }
+ return true;
+ }
+ bool sendExitCommand() {
+ GError *error = NULL;
+ int ret = searpc_client_call__int (
+ seafile_rpc_client_,
+ "exit",
+ &error, 0);
+ if (error) {
+ g_error_free(error);
+ return false;
+ }
+ if (ret != 0) {
+ return false;
+ }
+ return true;
+ }
+
+ bool sendOpenSeafileUrlCommand(const QUrl& url) {
+ GError *error = NULL;
+ int ret = searpc_client_call__int (
+ seafile_rpc_client_,
+ "open_seafile_url",
+ &error, 1, "string", url.toEncoded().data());
+ if (error) {
+ g_error_free(error);
+ return false;
+ }
+ if (ret != 0) {
+ return false;
+ }
+ return true;
+ }
+private:
+ SearpcClient *seafile_rpc_client_;
+
+};
+
+} // namespace
+
+struct SeafileAppletRpcServerPriv {
+ SearpcNamedPipeServer *pipe_server;
+};
+
+
+SINGLETON_IMPL(SeafileAppletRpcServer)
+
+SeafileAppletRpcServer::SeafileAppletRpcServer()
+: priv_(new SeafileAppletRpcServerPriv)
+{
+ priv_->pipe_server = searpc_create_named_pipe_server(toCStr(getAppletRpcPipePath()));
+
+ RpcServerProxy *proxy = RpcServerProxy::instance();
+ connect(
+ proxy, SIGNAL(activateCommand()), this, SLOT(handleActivateCommand()));
+ connect(proxy, SIGNAL(exitCommand()), this, SLOT(handleExitCommand()));
+ connect(proxy,
+ SIGNAL(openSeafileUrlCommand(const QUrl &)),
+ this,
+ SLOT(handleOpenSeafileUrlCommand(const QUrl &)));
+}
+
+SeafileAppletRpcServer::~SeafileAppletRpcServer()
+{
+}
+
+void SeafileAppletRpcServer::start()
+{
+ register_rpc_service();
+ qWarning("starting applet rpc service");
+ if (searpc_named_pipe_server_start(priv_->pipe_server) < 0) {
+ qWarning("failed to start rpc service");
+ seafApplet->errorAndExit("failed to initialize");
+ } else {
+ qWarning("applet rpc service started");
+ }
+}
+
+SeafileAppletRpcServer::Client* SeafileAppletRpcServer::getClient()
+{
+ return new AppletRpcClient();
+}
+
+void SeafileAppletRpcServer::handleActivateCommand()
+{
+ seafApplet->mainWindow()->showWindow();
+}
+
+void SeafileAppletRpcServer::handleExitCommand()
+{
+ qWarning("[Message Listener] Got a quit command. Quit now.");
+ QCoreApplication::exit(0);
+}
+
+void SeafileAppletRpcServer::handleOpenSeafileUrlCommand(const QUrl& url)
+{
+ OpenLocalHelper::instance()->openLocalFile(url);
+}
+
+
+SINGLETON_IMPL(RpcServerProxy)
+
+RpcServerProxy::RpcServerProxy()
+{
+}
+
+void RpcServerProxy::proxyActivateCommand()
+{
+ emit activateCommand();
+}
+
+void RpcServerProxy::proxyExitCommand()
+{
+ emit exitCommand();
+}
+
+void RpcServerProxy::proxyOpenSeafileUrlCommand(const QUrl& url)
+{
+ emit openSeafileUrlCommand(url);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_RPC_SERVER_H
+#define SEAFILE_CLIENT_RPC_SERVER_H
+
+#include <QObject>
+
+#include "utils/singleton.h"
+
+struct SeafileAppletRpcServerPriv;
+
+// This is the rpc server componet to accept commands like --stop,
+// --remove-user-data, and open seafile:// protocol url, etc.
+class SeafileAppletRpcServer : public QObject {
+ SINGLETON_DEFINE(SeafileAppletRpcServer)
+ Q_OBJECT
+public:
+ SeafileAppletRpcServer();
+ ~SeafileAppletRpcServer();
+
+ void start();
+
+ class Client {
+ public:
+ virtual bool connect() = 0;
+ virtual bool sendPingCommand(QString* resp) = 0;
+ virtual bool sendActivateCommand() = 0;
+ virtual bool sendExitCommand() = 0;
+ virtual bool sendOpenSeafileUrlCommand(const QUrl& url) = 0;
+ };
+
+ static Client* getClient();
+
+private slots:
+ void handleActivateCommand();
+ void handleExitCommand();
+ void handleOpenSeafileUrlCommand(const QUrl& url);
+
+private:
+ SeafileAppletRpcServerPriv *priv_;
+};
+
+// Helper object to proxy the rpc commands from the rpc server thread
+// to the main thread (using signals/slots). We need this because,
+// e.g. we can't call QCoreApplication::exit() from non-main thread.
+class RpcServerProxy : public QObject {
+ SINGLETON_DEFINE(RpcServerProxy)
+ Q_OBJECT
+
+public:
+ RpcServerProxy();
+
+ void proxyExitCommand();
+ void proxyActivateCommand();
+ void proxyOpenSeafileUrlCommand(const QUrl&);
+
+signals:
+ void exitCommand();
+ void activateCommand();
+ void openSeafileUrlCommand(const QUrl&);
+};
+
+#endif
--- /dev/null
+"""
+Define RPC functions needed to generate
+"""
+
+# [ <ret-type>, [<arg_types>] ]
+func_table = [
+ [ "int", [] ],
+ [ "int", ["string"] ],
+ [ "string", [] ],
+]
--- /dev/null
+
+static char *
+marshal_int__void (void *func, json_t *param_array, gsize *ret_len)
+{
+ GError *error = NULL;
+
+ int ret = ((int (*)(GError **))func) (&error);
+
+ json_t *object = json_object ();
+ searpc_set_int_to_ret_object (object, ret);
+ return searpc_marshal_set_ret_common (object, ret_len, error);
+}
+
+
+static char *
+marshal_int__string (void *func, json_t *param_array, gsize *ret_len)
+{
+ GError *error = NULL;
+ const char* param1 = json_array_get_string_or_null_element (param_array, 1);
+
+ int ret = ((int (*)(const char*, GError **))func) (param1, &error);
+
+ json_t *object = json_object ();
+ searpc_set_int_to_ret_object (object, ret);
+ return searpc_marshal_set_ret_common (object, ret_len, error);
+}
+
+
+static char *
+marshal_string__void (void *func, json_t *param_array, gsize *ret_len)
+{
+ GError *error = NULL;
+
+ char* ret = ((char* (*)(GError **))func) (&error);
+
+ json_t *object = json_object ();
+ searpc_set_string_to_ret_object (object, ret);
+ return searpc_marshal_set_ret_common (object, ret_len, error);
+}
+
+static void register_marshals()
+{
+
+ {
+ searpc_server_register_marshal (searpc_signature_int__void(), marshal_int__void);
+ }
+
+
+ {
+ searpc_server_register_marshal (searpc_signature_int__string(), marshal_int__string);
+ }
+
+
+ {
+ searpc_server_register_marshal (searpc_signature_string__void(), marshal_string__void);
+ }
+
+}
--- /dev/null
+
+inline static gchar *
+searpc_signature_int__void()
+{
+ return searpc_compute_signature ("int", 0);
+}
+
+
+inline static gchar *
+searpc_signature_int__string()
+{
+ return searpc_compute_signature ("int", 1, "string");
+}
+
+
+inline static gchar *
+searpc_signature_string__void()
+{
+ return searpc_compute_signature ("string", 0);
+}
+
--- /dev/null
+#include <QObject>
+#include <QStringList>
+#include <glib-object.h>
+
+#include "utils/utils.h"
+#include "sync-error.h"
+#include "utils/seafile-error.h"
+
+SyncError SyncError::fromGObject(GObject *obj)
+{
+ SyncError error;
+
+ int id = 0;
+ char *repo_id = NULL;
+ char *repo_name = NULL;
+ char *path = NULL;
+ int error_id = 0;
+ qint64 timestamp = 0;
+
+ g_object_get (obj,
+ "id", &id,
+ "repo_id", &repo_id,
+ "repo_name", &repo_name,
+ "path", &path,
+ "err_id", &error_id,
+ "timestamp", ×tamp,
+ NULL);
+
+ error.id = id;
+ error.repo_id = repo_id;
+ error.repo_name = QString::fromUtf8(repo_name);
+ error.path = QString::fromUtf8(path);
+
+ error.error_id = error_id;
+ error.timestamp = timestamp;
+
+ g_free (repo_id);
+ g_free (repo_name);
+ g_free (path);
+
+ error.translateErrorStr();
+
+ return error;
+}
+
+// SyncError only include file level and repository level
+void SyncError::translateErrorStr()
+{
+ readable_time_stamp = translateCommitTime(timestamp);
+
+ error_str = translateSyncErrorCode(error_id);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_RPC_SYNC_ERROR_H
+#define SEAFILE_CLIENT_RPC_SYNC_ERROR_H
+
+#include <QString>
+#include <QMetaType>
+
+struct _GObject;
+
+class SyncError {
+public:
+ int id;
+ QString repo_id;
+ QString repo_name;
+ QString path;
+ qint64 timestamp;
+ int error_id;
+
+ // Generated fields.
+ QString readable_time_stamp;
+ QString error_str;
+
+ static SyncError fromGObject(_GObject *obj);
+
+ void translateErrorStr();
+
+ bool operator==(const SyncError& rhs) const {
+ return id == rhs.id
+ && repo_id == rhs.repo_id
+ && repo_name == rhs.repo_name
+ && path == rhs.path
+ && error_id == rhs.error_id
+ && timestamp == rhs.timestamp;
+ }
+
+ bool operator!=(const SyncError& rhs) const {
+ return !(*this == rhs);
+ }
+};
+
+#endif // SEAFILE_CLIENT_RPC_SYNC_ERROR_H
--- /dev/null
+#!/bin/bash
+
+set -e
+
+# this seems to cover the bases on OSX, and someone will
+# have to tell me about the others.
+get_script_path () {
+ local path="$1"
+ [[ -L "$path" ]] || { echo "$path" ; return; }
+
+ local target="$(readlink "$path")"
+ if [[ "${target:0:1}" == "/" ]]; then
+ echo "$target"
+ else
+ echo "${path%/*}/$target"
+ fi
+}
+
+declare -r script_path="$(get_script_path "$BASH_SOURCE")"
+declare -r script_dir="${script_path%/*}"
+
+cd $script_dir
+searpc-codegen.py rpc_table.py
--- /dev/null
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QApplication>
+#include <QDesktopServices>
+#include <QFile>
+#include <QTextStream>
+#include <QDir>
+#include <QCoreApplication>
+#include <QMessageBox>
+#include <QTimer>
+#include <QHostInfo>
+
+#include <errno.h>
+#include <glib.h>
+
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/log.h"
+#include "account-mgr.h"
+#include "configurator.h"
+#include "daemon-mgr.h"
+#include "message-poller.h"
+#include "settings-mgr.h"
+#include "certs-mgr.h"
+#include "rpc/rpc-client.h"
+#include "ui/main-window.h"
+#include "ui/tray-icon.h"
+#include "ui/settings-dialog.h"
+#include "ui/init-vdrive-dialog.h"
+#include "ui/login-dialog.h"
+#include "open-local-helper.h"
+#include "avatar-service.h"
+#include "filebrowser/thumbnail-service.h"
+#include "filebrowser/data-cache.h"
+#include "filebrowser/auto-update-mgr.h"
+#include "filebrowser/data-mgr.h"
+#include "rpc/local-repo.h"
+#include "rpc/rpc-server.h"
+#include "network-mgr.h"
+#include "server-status-service.h"
+#include "account-info-service.h"
+#include "customization-service.h"
+
+#if defined(Q_OS_WIN32)
+ #include "ext-handler.h"
+ #include "utils/registry.h"
+#elif defined(HAVE_FINDER_SYNC_SUPPORT)
+ #include "finder-sync/finder-sync-listener.h"
+#endif
+
+#ifdef HAVE_SPARKLE_SUPPORT
+#include "auto-update-service.h"
+#endif
+
+
+#if defined(Q_OS_MAC)
+#include "utils/utils-mac.h"
+#endif
+
+#include "seafile-applet.h"
+
+namespace {
+enum DEBUG_LEVEL {
+ DEBUG = 0,
+ WARNING
+};
+
+// -DQT_NO_DEBUG is used with cmake and qmake if it is a release build
+// if it is debug build, use DEBUG level as default
+#if !defined(QT_NO_DEBUG) || !defined(NDEBUG)
+DEBUG_LEVEL seafile_client_debug_level = DEBUG;
+#else
+// if it is release build, use WARNING level as default
+DEBUG_LEVEL seafile_client_debug_level = WARNING;
+#endif
+
+void myLogHandlerDebug(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ QByteArray localMsg = msg.toLocal8Bit();
+ switch (type) {
+// Note: By default, this information (QMessageLogContext) is recorded only in debug builds.
+// You can overwrite this explicitly by defining QT_MESSAGELOGCONTEXT or QT_NO_MESSAGELOGCONTEXT.
+// from http://doc.qt.io/qt-5/qmessagelogcontext.html
+#ifdef QT_MESSAGELOGCONTEXT
+ case QtDebugMsg:
+ g_debug("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+ break;
+ case QtWarningMsg:
+ g_warning("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+ break;
+ case QtCriticalMsg:
+ g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+ break;
+ case QtFatalMsg:
+ g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+ abort();
+#else // QT_MESSAGELOGCONTEXT
+ case QtDebugMsg:
+ g_debug("%s\n", localMsg.constData());
+ break;
+ case QtWarningMsg:
+ g_warning("%s\n", localMsg.constData());
+ break;
+ case QtCriticalMsg:
+ g_critical("%s\n", localMsg.constData());
+ break;
+ case QtFatalMsg:
+ g_critical("%s\n", localMsg.constData());
+ abort();
+#endif // QT_MESSAGELOGCONTEXT
+ default:
+ break;
+ }
+}
+void myLogHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+{
+ QByteArray localMsg = msg.toLocal8Bit();
+ switch (type) {
+#ifdef QT_MESSAGELOGCONTEXT
+ case QtWarningMsg:
+ g_warning("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+ break;
+ case QtCriticalMsg:
+ g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+ break;
+ case QtFatalMsg:
+ g_critical("%s (%s:%u)\n", localMsg.constData(), context.file, context.line);
+ abort();
+#else // QT_MESSAGELOGCONTEXT
+ case QtWarningMsg:
+ g_warning("%s\n", localMsg.constData());
+ break;
+ case QtCriticalMsg:
+ g_critical("%s\n", localMsg.constData());
+ break;
+ case QtFatalMsg:
+ g_critical("%s\n", localMsg.constData());
+ abort();
+#endif // QT_MESSAGELOGCONTEXT
+ default:
+ break;
+ }
+}
+
+#ifdef Q_OS_MAC
+void writeCABundleForCurl()
+{
+ QString ca_bundle_path = QDir(seafApplet->configurator()->seafileDir()).filePath("ca-bundle.pem");
+ QFile bundle(ca_bundle_path);
+ if (bundle.exists()) {
+ bundle.remove();
+ }
+ bundle.open(QIODevice::WriteOnly);
+ const std::vector<QByteArray> certs = utils::mac::getSystemCaCertificates();
+ for (size_t i = 0; i < certs.size(); i++) {
+ QList<QSslCertificate> list = QSslCertificate::fromData(certs[i], QSsl::Der);
+ foreach (const QSslCertificate& cert, list) {
+ bundle.write(cert.toPem());
+ }
+ }
+}
+#endif
+
+
+const char *const kPreconfigureUsername = "PreconfigureUsername";
+const char *const kPreconfigureUserToken = "PreconfigureUserToken";
+const char *const kPreconfigureServerAddr = "PreconfigureServerAddr";
+const char *const kPreconfigureComputerName = "PreconfigureComputerName";
+const char* const kPreConfiguretionBlockSize = "PreconfigureBlockSize";
+const char* const kHideConfigurationWizard = "HideConfigurationWizard";
+#if defined(Q_OS_WIN32)
+const char *const kSeafileConfigureFileName = "seafile.ini";
+const char *const kSeafileConfigurePath = "SOFTWARE\\Seafile";
+const int kIntervalBeforeShowInitVirtualDialog = 3000;
+#else
+const char *const kSeafileConfigureFileName = ".seafilerc";
+#endif
+const char *const kSeafilePreconfigureGroupName = "preconfigure";
+
+const int kIntervalForUpdateRepoProperty = 1000;
+
+const char *kRepoServerUrlProperty = "server-url";
+
+} // namespace
+
+
+SeafileApplet *seafApplet;
+
+SeafileApplet::SeafileApplet()
+ : configurator_(new Configurator),
+ account_mgr_(new AccountManager),
+ daemon_mgr_(new DaemonManager),
+ main_win_(NULL),
+ rpc_client_(new SeafileRpcClient),
+ message_poller_(new MessagePoller),
+ settings_dialog_(new SettingsDialog),
+ settings_mgr_(new SettingsManager),
+ certs_mgr_(new CertsManager),
+ data_mgr_(new DataManager),
+ started_(false),
+ in_exit_(false),
+ is_pro_(false),
+ about_to_quit_(false)
+{
+ tray_icon_ = new SeafileTrayIcon(this);
+ connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(onAboutToQuit()));
+}
+
+SeafileApplet::~SeafileApplet()
+{
+ NetworkStatusDetector::instance()->stop();
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+ finderSyncListenerStop();
+#endif
+ delete tray_icon_;
+ delete certs_mgr_;
+ delete settings_dialog_;
+ delete message_poller_;
+ delete rpc_client_;
+ delete account_mgr_;
+ // seafile-applet exit will inform seaf-daemon to clean sync token,
+ // so the class object deamon_mgr daemon_mgr_ dealloc after account_mgr_.
+
+ delete daemon_mgr_;
+ delete configurator_;
+ delete data_mgr_;
+ if (main_win_)
+ delete main_win_;
+#if defined(Q_OS_WIN32)
+ SeafileExtensionHandler::instance()->stop();
+
+#ifdef HAVE_SPARKLE_SUPPORT
+ AutoUpdateService::instance()->stop();
+#endif
+
+#endif
+}
+
+void SeafileApplet::start()
+{
+ refreshQss();
+
+ configurator_->checkInit();
+
+ initLog();
+
+ qDebug("client id is %s", toCStr(getUniqueClientId()));
+ account_mgr_->start();
+
+ certs_mgr_->start();
+
+ data_mgr_->start();
+
+#if defined(Q_OS_WIN32)
+ QString crash_rpt_path = QDir(configurator_->ccnetDir()).filePath("logs/seafile-crash-report.txt");
+ if (!g_setenv ("CRASH_RPT_PATH", toCStr(crash_rpt_path), FALSE))
+ qWarning("Failed to set CRASH_RPT_PATH env variable.\n");
+#endif
+
+#if defined(Q_OS_MAC)
+ writeCABundleForCurl();
+#endif
+
+ // Load system proxy information. This must be done before we start
+ // seaf-daemon.
+ settings_mgr_->writeSystemProxyInfo(
+ account_mgr_->currentAccount().serverUrl,
+ QDir(configurator_->seafileDir()).filePath("system-proxy.txt"));
+
+ FileCache::instance()->start();
+
+ //
+ // start daemons
+ //
+ daemon_mgr_->startSeafileDaemon();
+
+ connect(daemon_mgr_, SIGNAL(daemonStarted()),
+ this, SLOT(onDaemonStarted()));
+ connect(daemon_mgr_, SIGNAL(daemonRestarted()),
+ this, SLOT(onDaemonRestarted()));
+}
+
+void SeafileApplet::onDaemonStarted()
+{
+ //
+ // start daemon-related services
+ //
+ rpc_client_->connectDaemon();
+
+ // Sleep 500 millseconds to wait seafile registering services
+
+ msleep(500);
+
+ //
+ // load proxy settings (important)
+ //
+ settings_mgr_->loadSettings();
+
+ //
+ // start network-related services
+ //
+ NetworkStatusDetector::instance()->start();
+ AutoUpdateManager::instance()->start();
+
+ AvatarService::instance()->start();
+ ThumbnailService::instance()->start();
+
+ ServerStatusService::instance()->start();
+ CustomizationService::instance()->start();
+ AccountInfoService::instance()->start();
+ SeafileAppletRpcServer::instance()->start();
+
+ account_mgr_->updateServerInfoForAllAccounts();
+
+ //
+ // start ui part
+ //
+ main_win_ = new MainWindow;
+
+#if defined(Q_OS_MAC)
+ seafApplet->settingsManager()->setHideDockIcon(seafApplet->settingsManager()->hideDockIcon());
+#endif
+
+#ifdef XCODE_APP
+ if (configurator_->firstUse()) {
+ settings_mgr_->setAutoStart(true);
+ }
+#endif
+
+ if (configurator_->firstUse() || account_mgr_->accounts().size() == 0) {
+ do {
+ QString username = readPreconfigureExpandedString(kPreconfigureUsername);
+ QString token = readPreconfigureExpandedString(kPreconfigureUserToken);
+ QString url = readPreconfigureExpandedString(kPreconfigureServerAddr);
+ QString computer_name = readPreconfigureExpandedString(kPreconfigureComputerName, settingsManager()->getComputerName());
+ if (!computer_name.isEmpty())
+ settingsManager()->setComputerName(computer_name);
+ if (!username.isEmpty() && !token.isEmpty() && !url.isEmpty()) {
+ Account account(url, username, token);
+ account_mgr_->setCurrentAccount(account);
+ break;
+ }
+
+ if (readPreconfigureEntry(kHideConfigurationWizard).toInt())
+ break;
+ LoginDialog login_dialog;
+ login_dialog.exec();
+ } while (0);
+ } else if (!account_mgr_->accounts().empty()) {
+ const Account &account = account_mgr_->accounts()[0];
+ account_mgr_->removeNonautoLoginSyncTokens();
+ account_mgr_->validateAndUseAccount(account);
+ }
+
+ started_ = true;
+
+ if (configurator_->firstUse() || !settings_mgr_->hideMainWindowWhenStarted()) {
+ main_win_->showWindow();
+ }
+
+ tray_icon_->start();
+ tray_icon_->setState(SeafileTrayIcon::STATE_DAEMON_UP);
+ message_poller_->start();
+
+
+#if defined(Q_OS_WIN32)
+ QTimer::singleShot(kIntervalBeforeShowInitVirtualDialog, this, SLOT(checkInitVDrive()));
+ configurator_->installCustomUrlHandler();
+#endif
+
+ QString value;
+ if (seafApplet->rpcClient()->seafileGetConfig("client_name", &value) < 0 || value.isEmpty()) {
+ // We do this because clients before 6.0 don't set the "client_name" option.
+ seafApplet->rpcClient()->seafileSetConfig(
+ "client_name", settings_mgr_->getComputerName());
+ }
+
+ // Set the device id to the daemon so it can use it when generating commits.
+ // The "client_name" is not set here, but updated each time we call
+ // switch_account rpc.
+ if (rpc_client_->seafileGetConfig("client_id", &value) < 0 ||
+ value.isEmpty() || value != getUniqueClientId()) {
+ rpc_client_->seafileSetConfig("client_id", getUniqueClientId());
+ }
+
+ // pre-configure option to set the size of sync block.
+ QString block = readPreconfigureExpandedString(kPreConfiguretionBlockSize);
+ if (!block.isEmpty()) {
+ int block_size = block.toInt();
+ if (rpc_client_->seafileSetConfigInt("block_size", block_size) < 0) {
+ qDebug("setting sync block_size error");
+ }
+ }
+ QTimer::singleShot(kIntervalForUpdateRepoProperty,
+ this, SLOT(updateReposPropertyForHttpSync()));
+
+ //
+ // start finder/explorer extension handler
+ //
+#if defined(Q_OS_WIN32)
+ SeafileExtensionHandler::instance()->start();
+#elif defined(HAVE_FINDER_SYNC_SUPPORT)
+ finderSyncListenerStart();
+#endif
+
+#ifdef HAVE_SPARKLE_SUPPORT
+ if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+ AutoUpdateService::instance()->start();
+ }
+#endif
+}
+
+void SeafileApplet::checkInitVDrive()
+{
+ if (configurator_->firstUse() && account_mgr_->hasAccount()) {
+ const Account account = account_mgr_->currentAccount();
+ InitVirtualDriveDialog *dialog = new InitVirtualDriveDialog(account);
+ // Move the dialog to the left of the main window
+ int x = main_win_->pos().x() - dialog->rect().width() - 30;
+ int y = (QApplication::desktop()->screenGeometry().center() - dialog->rect().center()).y();
+ dialog->move(qMax(0, x), y);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+ }
+}
+
+void SeafileApplet::onAboutToQuit()
+{
+ about_to_quit_ = true;
+ tray_icon_->hide();
+ if (main_win_) {
+ main_win_->writeSettings();
+ }
+}
+// stop the main event loop and return to the main function
+void SeafileApplet::errorAndExit(const QString& error)
+{
+ if (in_exit_ || QCoreApplication::closingDown()) {
+ return;
+ }
+
+ in_exit_ = true;
+
+ warningBox(error);
+ // stop eventloop before exit and return to the main function
+ QCoreApplication::exit(1);
+}
+
+void SeafileApplet::restartApp()
+{
+ if (in_exit_ || QCoreApplication::closingDown()) {
+ return;
+ }
+
+ in_exit_ = true;
+
+ QStringList args = QApplication::arguments();
+
+ args.removeFirst();
+
+ // append delay argument
+ bool found = false;
+ Q_FOREACH(const QString& arg, args)
+ {
+ if (arg == "--delay" || arg == "-D") {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ args.push_back("--delay");
+
+ QProcess::startDetached(QApplication::applicationFilePath(), args);
+ QCoreApplication::quit();
+}
+
+void SeafileApplet::initLog()
+{
+ if (applet_log_init(toCStr(configurator_->ccnetDir())) < 0) {
+ errorAndExit(tr("Failed to initialize log: %s").arg(g_strerror(errno)));
+ } else {
+ // give a change to override DEBUG_LEVEL by environment
+ QString debug_level = qgetenv("SEAFILE_CLIENT_DEBUG");
+ if (!debug_level.isEmpty() && debug_level != "false" &&
+ debug_level != "0")
+ seafile_client_debug_level = DEBUG;
+
+ if (seafile_client_debug_level == DEBUG)
+ qInstallMessageHandler(myLogHandlerDebug);
+ else
+ qInstallMessageHandler(myLogHandler);
+ }
+}
+
+bool SeafileApplet::loadQss(const QString& path)
+{
+ QFile file(path);
+ if (!QFileInfo(file).exists()) {
+ return false;
+ }
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ return false;
+ }
+
+ QTextStream input(&file);
+ style_ += "\n";
+ style_ += input.readAll();
+ qApp->setStyleSheet(style_);
+
+ return true;
+}
+
+void SeafileApplet::refreshQss()
+{
+ style_.clear();
+ loadQss("qt.css") || loadQss(":/qt.css");
+
+#if defined(Q_OS_WIN32)
+ loadQss("qt-win.css") || loadQss(":/qt-win.css");
+#elif defined(Q_OS_LINUX)
+ loadQss("qt-linux.css") || loadQss(":/qt-linux.css");
+#else
+ loadQss("qt-mac.css") || loadQss(":/qt-mac.css");
+#endif
+}
+
+void SeafileApplet::warningBox(const QString& msg, QWidget *parent)
+{
+ QMessageBox box(parent ? parent : main_win_);
+ box.setText(msg);
+ box.setWindowTitle(getBrand());
+ box.setIcon(QMessageBox::Warning);
+ box.addButton(tr("OK"), QMessageBox::YesRole);
+ box.exec();
+
+ if (!parent && main_win_) {
+ main_win_->showWindow();
+ }
+ qWarning("%s", msg.toUtf8().data());
+}
+
+void SeafileApplet::messageBox(const QString& msg, QWidget *parent)
+{
+ QMessageBox box(parent ? parent : main_win_);
+ box.setText(msg);
+ box.setWindowTitle(getBrand());
+ box.setIcon(QMessageBox::Information);
+ box.addButton(tr("OK"), QMessageBox::YesRole);
+ if (!parent) {
+ main_win_->showWindow();
+ }
+ box.exec();
+ qDebug("%s", msg.toUtf8().data());
+}
+
+bool SeafileApplet::yesOrNoBox(const QString& msg, QWidget *parent, bool default_val)
+{
+ QMessageBox box(parent ? parent : main_win_);
+ box.setText(msg);
+ box.setWindowTitle(getBrand());
+ box.setIcon(QMessageBox::Question);
+ QPushButton *yes_btn = box.addButton(tr("Yes"), QMessageBox::YesRole);
+ QPushButton *no_btn = box.addButton(tr("No"), QMessageBox::NoRole);
+ box.setDefaultButton(default_val ? yes_btn: no_btn);
+ box.exec();
+
+ return box.clickedButton() == yes_btn;
+}
+
+bool SeafileApplet::yesOrCancelBox(const QString& msg, QWidget *parent, bool default_yes)
+{
+ QMessageBox box(parent ? parent : main_win_);
+ box.setText(msg);
+ box.setWindowTitle(getBrand());
+ box.setIcon(QMessageBox::Question);
+ QPushButton *yes_btn = box.addButton(tr("Yes"), QMessageBox::YesRole);
+ QPushButton *cancel_btn = box.addButton(tr("Cancel"), QMessageBox::RejectRole);
+ box.setDefaultButton(default_yes ? yes_btn: cancel_btn);
+ box.exec();
+
+ return box.clickedButton() == yes_btn;
+}
+
+
+QMessageBox::StandardButton
+SeafileApplet::yesNoCancelBox(const QString& msg, QWidget *parent, QMessageBox::StandardButton default_btn)
+{
+ QMessageBox box(parent ? parent : main_win_);
+ box.setText(msg);
+ box.setWindowTitle(getBrand());
+ box.setIcon(QMessageBox::Question);
+ QPushButton *yes_btn = box.addButton(tr("Yes"), QMessageBox::YesRole);
+ QPushButton *no_btn = box.addButton(tr("No"), QMessageBox::NoRole);
+ box.addButton(tr("Cancel"), QMessageBox::RejectRole);
+ box.setDefaultButton(default_btn);
+ box.exec();
+
+ QAbstractButton *btn = box.clickedButton();
+ if (btn == yes_btn) {
+ return QMessageBox::Yes;
+ } else if (btn == no_btn) {
+ return QMessageBox::No;
+ }
+
+ return QMessageBox::Cancel;
+}
+
+bool SeafileApplet::detailedYesOrNoBox(const QString& msg, const QString& detailed_text, QWidget *parent, bool default_val)
+{
+ QMessageBox msgBox(QMessageBox::Question,
+ getBrand(),
+ msg,
+ QMessageBox::Yes | QMessageBox::No,
+ parent != 0 ? parent : main_win_);
+ msgBox.setDetailedText(detailed_text);
+ msgBox.setButtonText(QMessageBox::Yes, tr("Yes"));
+ msgBox.setButtonText(QMessageBox::No, tr("No"));
+ // Turns out the layout box in the QMessageBox is a grid
+ // You can force the resize using a spacer this way:
+ QSpacerItem* horizontalSpacer = new QSpacerItem(400, 0, QSizePolicy::Minimum, QSizePolicy::Expanding);
+ QGridLayout* layout = (QGridLayout*)msgBox.layout();
+ layout->addItem(horizontalSpacer, layout->rowCount(), 0, 1, layout->columnCount());
+ msgBox.setDefaultButton(default_val ? QMessageBox::Yes : QMessageBox::No);
+ return msgBox.exec() == QMessageBox::Yes;
+}
+
+/**
+ * For each repo, add the "server-url" property (inferred from account url),
+ * which would be used for http sync.
+ */
+void SeafileApplet::updateReposPropertyForHttpSync()
+{
+ std::vector<LocalRepo> repos;
+ if (rpc_client_->listLocalRepos(&repos) < 0) {
+ QTimer::singleShot(kIntervalForUpdateRepoProperty,
+ this, SLOT(updateReposPropertyForHttpSync()));
+ return;
+ }
+
+ const std::vector<Account>& accounts = account_mgr_->accounts();
+ for (size_t i = 0; i < repos.size(); i++) {
+ const LocalRepo& repo = repos[i];
+ QString repo_server_url;
+ QString server_url;
+ if (rpc_client_->getRepoProperty(repo.id, kRepoServerUrlProperty, &repo_server_url) < 0) {
+ continue;
+ }
+ if (!repo_server_url.isEmpty()) {
+ continue;
+ }
+ if (rpc_client_->getRepoProperty(repo.id, kRepoServerUrlProperty, &server_url) < 0) {
+ continue;
+ }
+
+ QString server_host = QUrl(server_url).host();
+ for (size_t i = 0; i < accounts.size(); i++) {
+ const Account& account = accounts[i];
+ if (account.serverUrl.host() == server_host) {
+ QUrl url(account.serverUrl);
+ url.setPath("/");
+ rpc_client_->setRepoProperty(repo.id, kRepoServerUrlProperty, url.toString());
+ break;
+ }
+ }
+ }
+}
+
+QVariant SeafileApplet::readPreconfigureEntry(const QString& key, const QVariant& default_value)
+{
+#ifdef Q_OS_WIN32
+ QVariant v = RegElement::getPreconfigureValue(key);
+ if (!v.isNull()) {
+ return v;
+ }
+#endif
+ QString configure_file = QDir::home().filePath(kSeafileConfigureFileName);
+ if (!QFileInfo(configure_file).exists())
+ return default_value;
+ QSettings setting(configure_file, QSettings::IniFormat);
+ setting.beginGroup(kSeafilePreconfigureGroupName);
+ QVariant value = setting.value(key, default_value);
+ setting.endGroup();
+ return value;
+}
+
+QString SeafileApplet::readPreconfigureExpandedString(const QString& key, const QString& default_value)
+{
+ QVariant retval = readPreconfigureEntry(key, default_value);
+ if (retval.isNull() || retval.type() != QVariant::String)
+ return QString();
+ return expandVars(retval.toString());
+}
+
+
+QString SeafileApplet::getText(QWidget *parent,
+ const QString &title,
+ const QString &label,
+ QLineEdit::EchoMode mode,
+ const QString &text,
+ bool *ok,
+ Qt::WindowFlags flags,
+ Qt::InputMethodHints inputMethodHints)
+{
+ QInputDialog tmp_dialog;
+ // Get rid of the help button
+ if (flags == 0) {
+ flags = tmp_dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint;
+ }
+
+ return QInputDialog::getText(parent != nullptr ? parent : main_win_,
+ title,
+ label,
+ mode,
+ text,
+ ok,
+ flags,
+ inputMethodHints);
+}
+
+QString SeafileApplet::getUniqueClientId()
+{
+ static QString id;
+ if (!id.isEmpty()) {
+ return id;
+ }
+
+ // Id file path is `~/Seafile/.seafile-data/id`
+ QFile id_file(QDir(seafApplet->configurator()->seafileDir())
+ .absoluteFilePath("id"));
+ if (!id_file.exists()) {
+ qWarning("id file not found, creating it");
+ // First migrate existing id from ccnet.conf General.ID
+ QString ccnet_conf_file = QDir(configurator_->ccnetDir()).absoluteFilePath("ccnet.conf");
+ QString ccnet_id;
+ if (QFile(ccnet_conf_file).exists()) {
+ QSettings ccnet_conf(ccnet_conf_file, QSettings::IniFormat);
+ ccnet_id = ccnet_conf.value("ID").toString();
+ if (ccnet_id.isEmpty()) {
+ ccnet_conf.beginGroup("General");
+ ccnet_id = ccnet_conf.value("ID", "").toString();
+ }
+ }
+
+ if (!ccnet_id.isEmpty()) {
+ id = ccnet_id;
+ qWarning("use existing ccnet id %s", toCStr(id));
+ } else {
+ srand(time(NULL));
+ while (id.length() < 40) {
+ int r = rand() % 0xff;
+ id += QString("%1").arg(r, 0, 16);
+ }
+ id = id.mid(0, 40);
+ qWarning("generated new device id %s", toCStr(id));
+ }
+
+ if (!id_file.open(QIODevice::WriteOnly)) {
+ errorAndExit(tr("failed to save client id"));
+ return "";
+ }
+
+ id_file.write(id.toUtf8().data());
+ return id;
+ }
+
+ if (!id_file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ errorAndExit(tr("failed to access %1").arg(id_file.fileName()));
+ return "";
+ }
+
+ QTextStream input(&id_file);
+ input.setCodec("UTF-8");
+
+ if (input.atEnd()) {
+ errorAndExit(tr("incorrect client id"));
+ return "";
+ }
+
+ id = input.readLine().trimmed();
+ if (id.length() != 40) {
+ errorAndExit(tr("failed to read %1").arg(id_file.fileName()));
+ return "";
+ }
+
+ qWarning("read id from id file");
+ return id;
+}
+
+void SeafileApplet::onDaemonRestarted()
+{
+ qDebug("reviving rpc client when daemon is restarted");
+ if (rpc_client_) {
+ delete rpc_client_;
+ }
+
+ rpc_client_ = new SeafileRpcClient();
+ rpc_client_->tryConnectDaemon();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_APPLET_H
+#define SEAFILE_CLIENT_APPLET_H
+
+#include <QObject>
+#include <QVariant>
+#include <QMessageBox>
+#include <QLineEdit>
+
+class Configurator;
+class DaemonManager;
+class SeafileRpcClient;
+class AccountManager;
+class MainWindow;
+class MessagePoller;
+class SeafileTrayIcon;
+class SettingsManager;
+class SettingsDialog;
+class CertsManager;
+class DataManager;
+
+
+/**
+ * The central class of seafile-client
+ */
+class SeafileApplet : QObject {
+ Q_OBJECT
+
+public:
+ SeafileApplet();
+ ~SeafileApplet();
+
+ void start();
+
+ void refreshQss();
+
+ void messageBox(const QString& msg, QWidget *parent=0);
+ void warningBox(const QString& msg, QWidget *parent=0);
+ bool yesOrNoBox(const QString& msg, QWidget *parent=0, bool default_val=true);
+ bool detailedYesOrNoBox(const QString& msg, const QString& detailed_text, QWidget *parent, bool default_val=true);
+ QMessageBox::StandardButton yesNoCancelBox(const QString& msg,
+ QWidget *parent,
+ QMessageBox::StandardButton default_btn);
+ bool yesOrCancelBox(const QString& msg, QWidget *parent, bool default_ok);
+
+ QString getText(QWidget *parent,
+ const QString &title,
+ const QString &label,
+ QLineEdit::EchoMode mode = QLineEdit::Normal,
+ const QString &text = QString(),
+ bool *ok = 0,
+ Qt::WindowFlags flags = 0,
+ Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
+
+ // Show error in a messagebox and exit
+ void errorAndExit(const QString &error);
+ void restartApp();
+
+ // Read preconfigure settings
+ QVariant readPreconfigureEntry(const QString& key, const QVariant& default_value = QVariant());
+ // ExpandedVars String
+ QString readPreconfigureExpandedString(const QString& key, const QString& default_value = QString());
+
+ // Create a unique device id to replace obselete ccnet id
+ QString getUniqueClientId();
+
+ // accessors
+ AccountManager *accountManager() { return account_mgr_; }
+
+ SeafileRpcClient *rpcClient() { return rpc_client_; }
+
+ DaemonManager *daemonManager() { return daemon_mgr_; }
+
+ Configurator *configurator() { return configurator_; }
+
+ MainWindow *mainWindow() { return main_win_; }
+
+ SeafileTrayIcon *trayIcon() { return tray_icon_; }
+
+ SettingsDialog *settingsDialog() { return settings_dialog_; }
+
+ SettingsManager *settingsManager() { return settings_mgr_; }
+
+ CertsManager *certsManager() { return certs_mgr_; }
+
+ DataManager *dataManager() { return data_mgr_; }
+
+ bool started() { return started_; }
+ bool closingDown() { return in_exit_ || about_to_quit_; }
+
+private slots:
+ void onDaemonStarted();
+ void onDaemonRestarted();
+ void checkInitVDrive();
+ void updateReposPropertyForHttpSync();
+ void onAboutToQuit();
+
+private:
+ Q_DISABLE_COPY(SeafileApplet)
+
+ void initLog();
+
+ bool loadQss(const QString& path);
+
+ Configurator *configurator_;
+
+ AccountManager *account_mgr_;
+
+ DaemonManager *daemon_mgr_;
+
+ MainWindow* main_win_;
+
+ SeafileRpcClient *rpc_client_;
+
+ MessagePoller *message_poller_;
+
+ SeafileTrayIcon *tray_icon_;
+
+ SettingsDialog *settings_dialog_;
+
+ SettingsManager *settings_mgr_;
+
+ CertsManager *certs_mgr_;
+
+ DataManager *data_mgr_;
+
+ bool started_;
+
+ bool in_exit_;
+
+ QString style_;
+
+ bool is_pro_;
+
+ bool about_to_quit_;
+};
+
+/**
+ * The global SeafileApplet object
+ */
+extern SeafileApplet *seafApplet;
+
+#define STR(s) #s
+#define STRINGIZE(x) STR(x)
+
+#endif // SEAFILE_CLIENT_APPLET_H
--- /dev/null
+#include <QTimer>
+#include <QUrl>
+#include <QDesktopServices>
+
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "api/requests.h"
+#include "auto-login-service.h"
+
+#include "seahub-notifications-monitor.h"
+
+namespace {
+
+const int kRefreshSeahubMessagesInterval = 5000 * 60; // 5 min
+const char *kNotificationsUrl = "notification/list/";
+
+} // namespace
+
+
+SeahubNotificationsMonitor* SeahubNotificationsMonitor::singleton_;
+
+SeahubNotificationsMonitor* SeahubNotificationsMonitor::instance()
+{
+ if (singleton_ == NULL) {
+ static SeahubNotificationsMonitor instance;
+ singleton_ = &instance;
+ }
+
+ return singleton_;
+}
+
+SeahubNotificationsMonitor::SeahubNotificationsMonitor(QObject *parent)
+ : QObject(parent),
+ check_messages_req_(0),
+ in_refresh_(false),
+ unread_count_(0)
+{
+ refresh_timer_ = new QTimer(this);
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+}
+
+void SeahubNotificationsMonitor::start()
+{
+ resetStatus();
+
+ refresh_timer_->start(kRefreshSeahubMessagesInterval);
+
+ connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+ this, SLOT(onAccountChanged()));
+ refresh();
+}
+
+void SeahubNotificationsMonitor::onAccountChanged()
+{
+ refresh(true);
+}
+
+void SeahubNotificationsMonitor::resetStatus()
+{
+ setUnreadNotificationsCount(0);
+}
+
+void SeahubNotificationsMonitor::refresh()
+{
+ if (in_refresh_) {
+ return;
+ }
+
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ resetStatus();
+ return;
+ }
+
+ in_refresh_ = true;
+
+ if (check_messages_req_) {
+ check_messages_req_->deleteLater();
+ }
+
+ check_messages_req_ = new GetUnseenSeahubNotificationsRequest(account);
+
+ connect(check_messages_req_, SIGNAL(success(int)),
+ this, SLOT(onRequestSuccess(int)));
+ connect(check_messages_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onRequestFailed(const ApiError&)));
+
+ check_messages_req_->send();
+}
+
+void SeahubNotificationsMonitor::onRequestFailed(const ApiError& error)
+{
+ in_refresh_ = false;
+}
+
+void SeahubNotificationsMonitor::onRequestSuccess(int count)
+{
+ in_refresh_ = false;
+ setUnreadNotificationsCount(count);
+}
+
+void SeahubNotificationsMonitor::refresh(bool force)
+{
+ if (force) {
+ resetStatus();
+ in_refresh_ = false;
+ }
+
+ refresh();
+}
+
+void SeahubNotificationsMonitor::openNotificationsPageInBrowser()
+{
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ return;
+ }
+
+ AutoLoginService::instance()->startAutoLogin(kNotificationsUrl);
+
+ resetStatus();
+}
+
+void SeahubNotificationsMonitor::setUnreadNotificationsCount(int count)
+{
+ if (unread_count_ != count) {
+ unread_count_ = count;
+ emit notificationsChanged();
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SEAHUB_MESSAGES_MONITOR_
+#define SEAFILE_CLIENT_SEAHUB_MESSAGES_MONITOR_
+
+#include <QObject>
+
+class QTimer;
+
+class ApiError;
+class GetUnseenSeahubNotificationsRequest;
+
+class SeahubNotificationsMonitor : public QObject
+{
+ Q_OBJECT
+public:
+ static SeahubNotificationsMonitor* instance();
+
+ void start();
+ void refresh(bool force);
+
+ int getUnreadNotifications() const { return unread_count_; }
+
+ void openNotificationsPageInBrowser();
+
+public slots:
+ void refresh();
+
+signals:
+ void notificationsChanged();
+
+private slots:
+ void onRequestSuccess(int count);
+ void onRequestFailed(const ApiError& error);
+ void onAccountChanged();
+
+private:
+ SeahubNotificationsMonitor(QObject *parent=0);
+ static SeahubNotificationsMonitor *singleton_;
+
+ void resetStatus();
+ void setUnreadNotificationsCount(int count);
+
+ QTimer *refresh_timer_;
+ GetUnseenSeahubNotificationsRequest *check_messages_req_;
+ bool in_refresh_;
+
+ int unread_count_;
+};
+
+#endif // SEAFILE_CLIENT_SEAHUB_MESSAGES_MONITOR_
--- /dev/null
+#include <QTimer>
+
+#include "server-status-service.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+
+namespace {
+
+// const int kRefreshInterval = 3 * 60 * 1000; // 3 min
+// const int kRefreshIntervalForUnconnected = 30 * 1000; // 30 sec
+
+}
+
+SINGLETON_IMPL(ServerStatusService)
+
+ServerStatusService::ServerStatusService(QObject *parent)
+ : QObject(parent)
+{
+ refresh_timer_ = new QTimer(this);
+ refresh_unconnected_timer_ = new QTimer(this);
+ connect(refresh_timer_, SIGNAL(timeout()),
+ this, SLOT(refresh()));
+ connect(refresh_unconnected_timer_, SIGNAL(timeout()),
+ this, SLOT(refreshUnconnected()));
+ refresh();
+}
+
+void ServerStatusService::start()
+{
+ // refresh_timer_->start(kRefreshInterval);
+ // refresh_unconnected_timer_->start(kRefreshIntervalForUnconnected);
+}
+
+void ServerStatusService::stop()
+{
+ refresh_timer_->stop();
+ refresh_unconnected_timer_->stop();
+}
+
+void ServerStatusService::refresh(bool only_refresh_unconnected)
+{
+ const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+ for (size_t i = 0; i < accounts.size(); i++) {
+ const QUrl& url = accounts[i].serverUrl;
+ if (!accounts[i].isValid()) {
+ // No need to ping the server if account has already logged out
+ statuses_.remove(url.host());
+ emit serverStatusChanged();
+ continue;
+ }
+ if (requests_.contains(url.host())) {
+ continue;
+ }
+
+ if (!statuses_.contains(url.host())) {
+ statuses_[url.host()] = ServerStatus(url, true);
+ }
+
+ if (only_refresh_unconnected && isServerConnected(url)) {
+ continue;
+ }
+ pingServer(url);
+ }
+}
+
+void ServerStatusService::pingServer(const QUrl& url)
+{
+ PingServerRequest *req = new PingServerRequest(url);
+ connect(req, SIGNAL(success()),
+ this, SLOT(onPingServerSuccess()));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onPingServerFailed()));
+ req->send();
+ requests_[url.host()] = req;
+}
+
+
+void ServerStatusService::onPingServerSuccess()
+{
+ PingServerRequest *req = (PingServerRequest *)sender();
+ statuses_[req->url().host()] = ServerStatus(req->url(), true);
+ emit serverStatusChanged();
+ requests_.take(req->url().host())->deleteLater();
+}
+
+void ServerStatusService::onPingServerFailed()
+{
+ PingServerRequest *req = (PingServerRequest *)sender();
+ statuses_[req->url().host()] = ServerStatus(req->url(), false);
+ emit serverStatusChanged();
+ requests_.take(req->url().host())->deleteLater();
+}
+
+bool ServerStatusService::allServersConnected() const
+{
+ foreach (const ServerStatus& status, statuses()) {
+ if (!status.connected) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool ServerStatusService::allServersDisconnected() const
+{
+ if (statuses_.isEmpty()) {
+ return false;
+ }
+ foreach (const ServerStatus& status, statuses()) {
+ if (status.connected) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+bool ServerStatusService::isServerConnected(const QUrl& url) const
+{
+ return statuses_.value(url.host()).connected;
+}
+
+void ServerStatusService::updateOnSuccessfullRequest(const QUrl& url)
+{
+ updateOnRequestFinished(url, true);
+}
+
+void ServerStatusService::updateOnFailedRequest(const QUrl& url)
+{
+ updateOnRequestFinished(url, false);
+}
+
+void ServerStatusService::updateOnRequestFinished(const QUrl& url, bool no_network_error)
+{
+ if (seafApplet->closingDown()) {
+ return;
+ }
+ bool found = false;
+ const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+ for (size_t i = 0; i < accounts.size(); i++) {
+ if (url.host() == accounts[i].serverUrl.host()) {
+ if (!accounts[i].isValid()) {
+ // No need to update the server status if account has already logged out
+ statuses_.remove(url.host());
+ emit serverStatusChanged();
+ continue;
+ }
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ qWarning("ServerStatusService: ignore request for host \"%s\"", url.host().toUtf8().data());
+ return;
+ }
+
+ bool changed = false;
+ if (statuses_.contains(url.host())) {
+ const ServerStatus& status = statuses_[url.host()];
+ if (status.connected != no_network_error) {
+ changed = true;
+ }
+ }
+ statuses_[url.host()] = ServerStatus(url, no_network_error);
+
+ if (changed) {
+ emit serverStatusChanged();
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SERVER_STATUS_SERVICE_H
+#define SEAFILE_CLIENT_SERVER_STATUS_SERVICE_H
+
+#include <QObject>
+#include <QList>
+#include <QUrl>
+#include <QHash>
+
+#include "utils/singleton.h"
+
+class QTimer;
+
+class PingServerRequest;
+class ApiError;
+
+class ServerStatus {
+public:
+ ServerStatus() {}
+ ServerStatus(const QUrl& url, bool connected):
+ url(url),
+ connected(connected) {}
+
+ QUrl url;
+ bool connected;
+};
+
+class ServerStatusService : public QObject
+{
+ Q_OBJECT
+ SINGLETON_DEFINE(ServerStatusService)
+public:
+ void start();
+ void stop();
+
+ // accessors
+ const QList<ServerStatus> statuses() const { return statuses_.values(); }
+
+ bool allServersConnected() const;
+ bool allServersDisconnected() const;
+
+public slots:
+ void refresh(bool only_refresh_unconnected=false);
+ void refreshUnconnected() { refresh(true); }
+ void updateOnSuccessfullRequest(const QUrl& url);
+ void updateOnFailedRequest(const QUrl& url);
+
+private slots:
+ void onPingServerSuccess();
+ void onPingServerFailed();
+
+signals:
+ void serverStatusChanged();
+
+private:
+ Q_DISABLE_COPY(ServerStatusService)
+ ServerStatusService(QObject *parent=0);
+
+ void pingServer(const QUrl& url);
+ bool isServerConnected(const QUrl& url) const;
+ void updateOnRequestFinished(const QUrl& url, bool no_network_error);
+
+ QTimer *refresh_timer_;
+ QTimer *refresh_unconnected_timer_;
+
+ QHash<QString, ServerStatus> statuses_;
+ QHash<QString, PingServerRequest *> requests_;
+};
+
+
+#endif // SEAFILE_CLIENT_SERVER_STATUS_SERVICE_H
--- /dev/null
+#include <QHostInfo>
+#include <QNetworkProxy>
+#include <QNetworkProxyQuery>
+#include <QSettings>
+#include <QThreadPool>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "seafile-applet.h"
+#include "ui/tray-icon.h"
+#include "rpc/rpc-client.h"
+#include "utils/utils.h"
+#include "network-mgr.h"
+#include "ui/main-window.h"
+#include "account-mgr.h"
+
+#if defined(Q_OS_WIN32)
+#include "utils/registry.h"
+#endif
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+#include "finder-sync/finder-sync.h"
+#endif
+
+#include "settings-mgr.h"
+
+namespace
+{
+const char *kHideMainWindowWhenStarted = "hideMainWindowWhenStarted";
+const char *kHideDockIcon = "hideDockIcon";
+const char *kEnableSyncingWithExistingFolder = "syncingWithExistingFolder";
+const char *kBehaviorGroup = "Behavior";
+
+// const char *kDefaultLibraryAlreadySetup = "defaultLibraryAlreadySetup";
+// const char *kStatusGroup = "Status";
+
+const char *kSettingsGroup = "Settings";
+const char *kComputerName = "computerName";
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+const char *kFinderSync = "finderSync";
+#endif // HAVE_FINDER_SYNC_SUPPORT
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+const char *kLastShibUrl = "lastShiburl";
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+const char *kUseProxy = "use_proxy";
+const char *kUseSystemProxy = "use_system_proxy";
+const char *kProxyType = "proxy_type";
+const char *kProxyAddr = "proxy_addr";
+const char *kProxyPort = "proxy_port";
+const char *kProxyUsername = "proxy_username";
+const char *kProxyPassword = "proxy_password";
+
+const int kCheckSystemProxyIntervalMSecs = 5 * 1000;
+
+
+#ifdef Q_OS_WIN32
+QString softwareSeafile()
+{
+ return QString("SOFTWARE\\%1").arg(getBrand());
+}
+#endif
+
+
+bool getSystemProxyForUrl(const QUrl &url, QNetworkProxy *proxy)
+{
+ QNetworkProxyQuery query(url);
+ bool use_proxy = true;
+ QList<QNetworkProxy> proxies = QNetworkProxyFactory::systemProxyForQuery(query);
+
+ // printf("list of proxies: %d\n", proxies.size());
+ // foreach (const QNetworkProxy &proxy, proxies) {
+ // static int i = 0;
+ // printf("[proxy number %d] %d %s:%d %s %s \n", i++, (int)proxy.type(),
+ // proxy.hostName().toUtf8().data(), proxy.port(),
+ // proxy.user().toUtf8().data(),
+ // proxy.password().toUtf8().data());
+ // }
+
+ if (proxies.empty()) {
+ use_proxy = false;
+ } else {
+ *proxy = proxies[0];
+ if (proxy->type() == QNetworkProxy::NoProxy ||
+ proxy->type() == QNetworkProxy::DefaultProxy ||
+ proxy->type() == QNetworkProxy::FtpCachingProxy) {
+ use_proxy = false;
+ }
+
+ if (proxy->hostName().isEmpty() || proxy->port() == 0) {
+ use_proxy = false;
+ }
+ }
+
+ return use_proxy;
+}
+
+
+} // namespace
+
+
+SettingsManager::SettingsManager()
+ : auto_sync_(true),
+ bubbleNotifycation_(true),
+ autoStart_(false),
+ allow_invalid_worktree_(false),
+ allow_repo_not_found_on_server_(false),
+ sync_extra_temp_file_(false),
+ maxDownloadRatio_(0),
+ maxUploadRatio_(0),
+ verify_http_sync_cert_disabled_(false),
+ current_proxy_(SeafileProxy())
+{
+ check_system_proxy_timer_ = new QTimer(this);
+ connect(check_system_proxy_timer_, SIGNAL(timeout()), this, SLOT(checkSystemProxy()));
+}
+
+void SettingsManager::loadSettings()
+{
+ QString str;
+ int value;
+
+ if (seafApplet->rpcClient()->seafileGetConfig("notify_sync", &str) >= 0)
+ bubbleNotifycation_ = (str == "off") ? false : true;
+
+ if (seafApplet->rpcClient()->seafileGetConfigInt("download_limit",
+ &value) >= 0)
+ maxDownloadRatio_ = value >> 10;
+
+ if (seafApplet->rpcClient()->seafileGetConfigInt("upload_limit",
+ &value) >= 0)
+ maxUploadRatio_ = value >> 10;
+
+ if (seafApplet->rpcClient()->seafileGetConfig("allow_invalid_worktree",
+ &str) >= 0)
+ allow_invalid_worktree_ = (str == "true") ? true : false;
+
+ if (seafApplet->rpcClient()->seafileGetConfig("sync_extra_temp_file",
+ &str) >= 0)
+ sync_extra_temp_file_ = (str == "true") ? true : false;
+
+ if (seafApplet->rpcClient()->seafileGetConfig(
+ "allow_repo_not_found_on_server", &str) >= 0)
+ allow_repo_not_found_on_server_ = (str == "true") ? true : false;
+
+ if (seafApplet->rpcClient()->seafileGetConfig("disable_verify_certificate",
+ &str) >= 0)
+ verify_http_sync_cert_disabled_ = (str == "true") ? true : false;
+
+ loadProxySettings();
+ applyProxySettings();
+
+ autoStart_ = get_seafile_auto_start();
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+ // try to do a reinstall, or we may use findersync somewhere else
+ // this action won't stop findersync if running already
+ FinderSyncExtensionHelper::reinstall();
+
+ // try to sync finder sync extension settings with the actual settings
+ // i.e. enabling the finder sync if the setting is true
+ setFinderSyncExtension(getFinderSyncExtension());
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+
+#ifdef Q_OS_WIN32
+ RegElement reg(HKEY_CURRENT_USER, softwareSeafile(), "ShellExtDisabled",
+ "");
+ shell_ext_enabled_ = !reg.exists();
+#endif
+}
+
+void SettingsManager::loadProxySettings()
+{
+ SeafileProxy proxy;
+
+ QString use_proxy;
+ seafApplet->rpcClient()->seafileGetConfig(kUseProxy, &use_proxy);
+ if (use_proxy != "true") {
+ return;
+ }
+ QString use_system_proxy;
+ seafApplet->rpcClient()->seafileGetConfig(kUseSystemProxy, &use_system_proxy);
+ if (use_system_proxy == "true") {
+ current_proxy_.type = SystemProxy;
+ return;
+ }
+
+ QString proxy_type;
+ QString proxy_host;
+ int proxy_port;
+ QString proxy_username;
+ QString proxy_password;
+
+ if (seafApplet->rpcClient()->seafileGetConfig(kProxyAddr, &proxy_host) <
+ 0) {
+ return;
+ }
+ if (seafApplet->rpcClient()->seafileGetConfigInt(kProxyPort, &proxy_port) <
+ 0) {
+ return;
+ }
+ if (seafApplet->rpcClient()->seafileGetConfig(kProxyType, &proxy_type) <
+ 0) {
+ return;
+ }
+ if (proxy_type == "http") {
+ if (seafApplet->rpcClient()->seafileGetConfig(kProxyUsername,
+ &proxy_username) < 0) {
+ return;
+ }
+ if (seafApplet->rpcClient()->seafileGetConfig(kProxyPassword,
+ &proxy_password) < 0) {
+ return;
+ }
+ proxy.type = HttpProxy;
+ proxy.host = proxy_host;
+ proxy.port = proxy_port;
+ proxy.username = proxy_username;
+ proxy.password = proxy_password;
+
+ } else if (proxy_type == "socks") {
+ proxy.type = SocksProxy;
+ proxy.host = proxy_host;
+ proxy.port = proxy_port;
+ } else if (!proxy_type.isEmpty()) {
+ qWarning("Unsupported proxy_type %s", proxy_type.toUtf8().data());
+ return;
+ }
+
+ current_proxy_ = proxy;
+}
+
+
+void SettingsManager::setAutoSync(bool auto_sync)
+{
+ if (seafApplet->rpcClient()->setAutoSync(auto_sync) < 0) {
+ // Error
+ return;
+ }
+ auto_sync_ = auto_sync;
+ seafApplet->trayIcon()->setState(
+ auto_sync ? SeafileTrayIcon::STATE_DAEMON_UP
+ : SeafileTrayIcon::STATE_DAEMON_AUTOSYNC_DISABLED);
+ emit autoSyncChanged(auto_sync);
+}
+
+void SettingsManager::setNotify(bool notify)
+{
+ if (bubbleNotifycation_ != notify) {
+ if (seafApplet->rpcClient()->seafileSetConfig(
+ "notify_sync", notify ? "on" : "off") < 0) {
+ // Error
+ return;
+ }
+ bubbleNotifycation_ = notify;
+ }
+}
+
+void SettingsManager::setAutoStart(bool autoStart)
+{
+ if (autoStart_ != autoStart) {
+ if (set_seafile_auto_start(autoStart) >= 0)
+ autoStart_ = autoStart;
+ }
+}
+
+void SettingsManager::setMaxDownloadRatio(unsigned int ratio)
+{
+ if (maxDownloadRatio_ != ratio) {
+ if (seafApplet->rpcClient()->setDownloadRateLimit(ratio << 10) < 0) {
+ // Error
+ return;
+ }
+ maxDownloadRatio_ = ratio;
+ }
+}
+
+void SettingsManager::setMaxUploadRatio(unsigned int ratio)
+{
+ if (maxUploadRatio_ != ratio) {
+ if (seafApplet->rpcClient()->setUploadRateLimit(ratio << 10) < 0) {
+ // Error
+ return;
+ }
+ maxUploadRatio_ = ratio;
+ }
+}
+
+bool SettingsManager::hideMainWindowWhenStarted()
+{
+ QSettings settings;
+ bool hide;
+
+ settings.beginGroup(kBehaviorGroup);
+ hide = settings.value(kHideMainWindowWhenStarted, false).toBool();
+ settings.endGroup();
+
+ return hide;
+}
+
+void SettingsManager::setHideMainWindowWhenStarted(bool hide)
+{
+ QSettings settings;
+
+ settings.beginGroup(kBehaviorGroup);
+ settings.setValue(kHideMainWindowWhenStarted, hide);
+ settings.endGroup();
+}
+
+bool SettingsManager::hideDockIcon()
+{
+ QSettings settings;
+ bool hide;
+
+ settings.beginGroup(kBehaviorGroup);
+ hide = settings.value(kHideDockIcon, false).toBool();
+ settings.endGroup();
+ return hide;
+}
+
+void SettingsManager::setHideDockIcon(bool hide)
+{
+ QSettings settings;
+
+ settings.beginGroup(kBehaviorGroup);
+ settings.setValue(kHideDockIcon, hide);
+ settings.endGroup();
+
+ set_seafile_dock_icon_style(hide);
+#ifdef Q_OS_MAC
+ // for UIElement application, the main window might sink
+ // under many applications
+ // this will force it to stand before all
+ utils::mac::orderFrontRegardless(seafApplet->mainWindow()->winId());
+#endif
+}
+
+// void SettingsManager::setDefaultLibraryAlreadySetup()
+// {
+// QSettings settings;
+
+// settings.beginGroup(kStatusGroup);
+// settings.setValue(kDefaultLibraryAlreadySetup, true);
+// settings.endGroup();
+// }
+
+
+// bool SettingsManager::defaultLibraryAlreadySetup()
+// {
+// QSettings settings;
+// bool done;
+
+// settings.beginGroup(kStatusGroup);
+// done = settings.value(kDefaultLibraryAlreadySetup, false).toBool();
+// settings.endGroup();
+
+// return done;
+// }
+
+void SettingsManager::removeAllSettings()
+{
+ QSettings settings;
+ settings.clear();
+
+#if defined(Q_OS_WIN32)
+ RegElement::removeRegKey(HKEY_CURRENT_USER, "SOFTWARE", getBrand());
+#endif
+}
+
+void SettingsManager::setAllowInvalidWorktree(bool val)
+{
+ if (allow_invalid_worktree_ != val) {
+ if (seafApplet->rpcClient()->seafileSetConfig(
+ "allow_invalid_worktree", val ? "true" : "false") < 0) {
+ // Error
+ return;
+ }
+ allow_invalid_worktree_ = val;
+ }
+}
+
+void SettingsManager::setSyncExtraTempFile(bool sync)
+{
+ if (sync_extra_temp_file_ != sync) {
+ if (seafApplet->rpcClient()->seafileSetConfig(
+ "sync_extra_temp_file", sync ? "true" : "false") < 0) {
+ // Error
+ return;
+ }
+ sync_extra_temp_file_ = sync;
+ }
+}
+
+void SettingsManager::getProxy(QNetworkProxy *proxy) const
+{
+ current_proxy_.toQtNetworkProxy(proxy);
+ return;
+}
+
+void SettingsManager::SeafileProxy::toQtNetworkProxy(QNetworkProxy *proxy) const
+{
+ if (type == NoProxy) {
+ proxy->setType(QNetworkProxy::NoProxy);
+ return;
+ }
+ proxy->setType(type == HttpProxy ? QNetworkProxy::HttpProxy
+ : QNetworkProxy::Socks5Proxy);
+ proxy->setHostName(host);
+ proxy->setPort(port);
+ if (type == HttpProxy && !username.isEmpty() && !password.isEmpty()) {
+ proxy->setUser(username);
+ proxy->setPassword(password);
+ }
+}
+
+SettingsManager::SeafileProxy SettingsManager::SeafileProxy::fromQtNetworkProxy(
+ const QNetworkProxy &proxy)
+{
+ SeafileProxy sproxy;
+ if (proxy.type() == QNetworkProxy::NoProxy ||
+ proxy.type() == QNetworkProxy::DefaultProxy) {
+ sproxy.type = NoProxy;
+ return sproxy;
+ }
+
+ sproxy.host = proxy.hostName();
+ sproxy.port = proxy.port();
+
+ if (proxy.type() == QNetworkProxy::HttpProxy) {
+ sproxy.type = HttpProxy;
+ sproxy.username = proxy.user();
+ sproxy.password = proxy.password();
+ } else if (proxy.type() == QNetworkProxy::Socks5Proxy) {
+ sproxy.type = SocksProxy;
+ }
+
+ return sproxy;
+}
+
+bool SettingsManager::SeafileProxy::operator==(const SeafileProxy &rhs) const
+{
+ if (type != rhs.type) {
+ return false;
+ }
+ if (type == NoProxy || type == SystemProxy) {
+ return true;
+ } else if (type == HttpProxy) {
+ return host == rhs.host && port == rhs.port &&
+ username == rhs.username && password == rhs.password;
+ } else {
+ // socks proxy
+ return host == rhs.host && port == rhs.port;
+ }
+}
+
+void SettingsManager::setProxy(const SeafileProxy &proxy)
+{
+ if (proxy == current_proxy_) {
+ return;
+ }
+ current_proxy_ = proxy;
+
+ writeProxySettingsToDaemon(proxy);
+ applyProxySettings();
+}
+
+void SettingsManager::applyProxySettings()
+{
+ if (current_proxy_.type == SystemProxy) {
+ QNetworkProxyFactory::setUseSystemConfiguration(true);
+ if (!check_system_proxy_timer_->isActive()) {
+ check_system_proxy_timer_->start(kCheckSystemProxyIntervalMSecs);
+ }
+ return;
+ } else {
+ QNetworkProxyFactory::setUseSystemConfiguration(false);
+ if (check_system_proxy_timer_->isActive()) {
+ check_system_proxy_timer_->stop();
+ }
+
+ if (current_proxy_.type == NoProxy) {
+ QNetworkProxy::setApplicationProxy(QNetworkProxy::NoProxy);
+ }
+ }
+
+ QNetworkProxy proxy;
+ getProxy(&proxy);
+ NetworkManager::instance()->applyProxy(proxy);
+}
+
+void SettingsManager::writeProxySettingsToDaemon(const SeafileProxy &proxy)
+{
+ SeafileRpcClient *rpc = seafApplet->rpcClient();
+ if (proxy.type == NoProxy) {
+ rpc->seafileSetConfig(kUseProxy, "false");
+ return;
+ }
+
+ rpc->seafileSetConfig(kUseProxy, "true");
+ if (proxy.type == SystemProxy) {
+ rpc->seafileSetConfig(kUseSystemProxy, "true");
+ return;
+ } else {
+ rpc->seafileSetConfig(kUseSystemProxy, "false");
+ }
+
+ writeProxyDetailsToDaemon(proxy);
+}
+
+void SettingsManager::writeProxyDetailsToDaemon(const SeafileProxy& proxy)
+{
+ Q_ASSERT(proxy.type != NoProxy && proxy.type != SystemProxy);
+ SeafileRpcClient *rpc = seafApplet->rpcClient();
+ QString type = proxy.type == HttpProxy ? "http" : "socks";
+ rpc->seafileSetConfig(kProxyType, type);
+ rpc->seafileSetConfig(kProxyAddr, proxy.host.toUtf8().data());
+ rpc->seafileSetConfigInt(kProxyPort, proxy.port);
+ if (type == "http") {
+ rpc->seafileSetConfig(kProxyUsername, proxy.username.toUtf8().data());
+ rpc->seafileSetConfig(kProxyPassword, proxy.password.toUtf8().data());
+ }
+}
+
+void SettingsManager::setAllowRepoNotFoundOnServer(bool val)
+{
+ if (allow_repo_not_found_on_server_ != val) {
+ if (seafApplet->rpcClient()->seafileSetConfig(
+ "allow_repo_not_found_on_server", val ? "true" : "false") < 0) {
+ // Error
+ return;
+ }
+ allow_repo_not_found_on_server_ = val;
+ }
+}
+
+void SettingsManager::setHttpSyncCertVerifyDisabled(bool disabled)
+{
+ if (verify_http_sync_cert_disabled_ != disabled) {
+ if (seafApplet->rpcClient()->seafileSetConfig(
+ "disable_verify_certificate", disabled ? "true" : "false") <
+ 0) {
+ // Error
+ return;
+ }
+ verify_http_sync_cert_disabled_ = disabled;
+ }
+}
+
+bool SettingsManager::isEnableSyncingWithExistingFolder() const
+{
+ bool enabled;
+ QSettings settings;
+
+ settings.beginGroup(kBehaviorGroup);
+ enabled = settings.value(kEnableSyncingWithExistingFolder, false).toBool();
+ settings.endGroup();
+
+ return enabled;
+}
+
+void SettingsManager::setEnableSyncingWithExistingFolder(bool enabled)
+{
+ QSettings settings;
+
+ settings.beginGroup(kBehaviorGroup);
+ settings.setValue(kEnableSyncingWithExistingFolder, enabled);
+ settings.endGroup();
+}
+
+QString SettingsManager::getComputerName()
+{
+ QSettings settings;
+ QString name;
+
+ QString default_computer_Name = QHostInfo::localHostName();
+
+ settings.beginGroup(kSettingsGroup);
+ name = settings.value(kComputerName, default_computer_Name).toString();
+ settings.endGroup();
+
+ return name;
+}
+
+void SettingsManager::setComputerName(const QString &computerName)
+{
+ QSettings settings;
+ settings.beginGroup(kSettingsGroup);
+ settings.setValue(kComputerName, computerName);
+ settings.endGroup();
+
+ seafApplet->rpcClient()->seafileSetConfig("client_name", computerName);
+}
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+QString SettingsManager::getLastShibUrl()
+{
+ QSettings settings;
+ QString url;
+
+ settings.beginGroup(kSettingsGroup);
+ url = settings.value(kLastShibUrl, "").toString();
+ settings.endGroup();
+
+ return url;
+}
+
+void SettingsManager::setLastShibUrl(const QString &url)
+{
+ QSettings settings;
+ settings.beginGroup(kSettingsGroup);
+ settings.setValue(kLastShibUrl, url);
+ settings.endGroup();
+}
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+bool SettingsManager::getFinderSyncExtension() const
+{
+ QSettings settings;
+ bool enabled;
+
+ settings.beginGroup(kSettingsGroup);
+ enabled = settings.value(kFinderSync, true).toBool();
+ settings.endGroup();
+
+ return enabled;
+}
+bool SettingsManager::getFinderSyncExtensionAvailable() const
+{
+ return FinderSyncExtensionHelper::isInstalled();
+}
+void SettingsManager::setFinderSyncExtension(bool enabled)
+{
+ QSettings settings;
+
+ settings.beginGroup(kSettingsGroup);
+ settings.setValue(kFinderSync, enabled);
+ settings.endGroup();
+
+ // if setting operation fails
+ if (!getFinderSyncExtensionAvailable()) {
+ qWarning("Unable to find FinderSync Extension");
+ } else if (enabled != FinderSyncExtensionHelper::isEnabled() &&
+ !FinderSyncExtensionHelper::setEnable(enabled)) {
+ qWarning("Unable to enable FinderSync Extension");
+ }
+}
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+#ifdef Q_OS_WIN32
+void SettingsManager::setShellExtensionEnabled(bool enabled)
+{
+ shell_ext_enabled_ = enabled;
+
+ RegElement reg1(HKEY_CURRENT_USER, softwareSeafile(), "", "");
+ RegElement reg2(HKEY_CURRENT_USER, softwareSeafile(), "ShellExtDisabled",
+ "1");
+ if (enabled) {
+ reg2.remove();
+ } else {
+ reg1.add();
+ reg2.add();
+ }
+}
+#endif // Q_OS_WIN32
+
+
+void SettingsManager::writeSystemProxyInfo(const QUrl &url,
+ const QString &file_path)
+{
+ QNetworkProxy proxy;
+ bool use_proxy = getSystemProxyForUrl(url, &proxy);
+
+ QString content;
+ if (use_proxy) {
+ QString type;
+ if (proxy.type() == QNetworkProxy::HttpProxy ||
+ proxy.type() == QNetworkProxy::HttpCachingProxy) {
+ type = "http";
+ } else {
+ type = "socks";
+ }
+ QString json_content =
+ "{\"type\": \"%1\", \"addr\": \"%2\", \"port\": %3, \"username\": "
+ "\"%4\", \"password\": \"%5\"}";
+ content = json_content.arg(type)
+ .arg(proxy.hostName())
+ .arg(proxy.port())
+ .arg(proxy.user())
+ .arg(proxy.password());
+ } else {
+ content = "{\"type\": \"none\"}";
+ }
+
+ QFile system_proxy_txt(file_path);
+ if (!system_proxy_txt.open(QIODevice::WriteOnly)) {
+ return;
+ }
+
+ system_proxy_txt.write(content.toUtf8().data());
+}
+
+void SettingsManager::checkSystemProxy()
+{
+ if (current_proxy_.type != SystemProxy) {
+ // qDebug ("current proxy is not system proxy, return\n");
+ return;
+ }
+
+ const Account &account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ return;
+ }
+
+ SystemProxyPoller *poller = new SystemProxyPoller(account.serverUrl);
+ connect(poller, SIGNAL(systemProxyPolled(const QNetworkProxy &)), this,
+ SLOT(onSystemProxyPolled(const QNetworkProxy &)));
+
+ QThreadPool::globalInstance()->start(poller);
+}
+
+
+void SettingsManager::onSystemProxyPolled(const QNetworkProxy &system_proxy)
+{
+ if (current_proxy_.type != SystemProxy) {
+ return;
+ }
+ if (last_system_proxy_ == system_proxy) {
+ // qDebug ("system proxy not changed\n");
+ return;
+ }
+ // qDebug ("system proxy changed\n");
+ last_system_proxy_ = system_proxy;
+ SeafileProxy proxy = SeafileProxy::fromQtNetworkProxy(system_proxy);
+ if (proxy.type == NoProxy) {
+ // qDebug ("system proxy changed to no proxy\n");
+ seafApplet->rpcClient()->seafileSetConfig(kProxyType, "none");
+ } else {
+ writeProxyDetailsToDaemon(proxy);
+ }
+}
+
+SystemProxyPoller::SystemProxyPoller(const QUrl &url) : url_(url)
+{
+}
+
+void SystemProxyPoller::run()
+{
+ QNetworkProxy proxy;
+ bool use_proxy = getSystemProxyForUrl(url_, &proxy);
+ if (!use_proxy) {
+ proxy.setType(QNetworkProxy::NoProxy);
+ }
+ emit systemProxyPolled(proxy);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SETTINGS_MANAGER_H
+#define SEAFILE_CLIENT_SETTINGS_MANAGER_H
+
+#include <QObject>
+#include <QRunnable>
+#include <QUrl>
+#include <QNetworkProxy>
+
+/**
+ * Settings Manager handles seafile client user settings & preferences
+ */
+class QTimer;
+
+class SettingsManager : public QObject {
+ Q_OBJECT
+
+public:
+ enum ProxyType {
+ NoProxy = 0,
+ HttpProxy = 1,
+ SocksProxy = 2,
+ SystemProxy = 3
+ };
+
+ struct SeafileProxy {
+ ProxyType type;
+
+ QString host;
+ int port;
+ QString username;
+ QString password;
+
+ SeafileProxy(ProxyType _type = NoProxy,
+ const QString _host = QString(),
+ int _port = 0,
+ const QString& _username = QString(),
+ const QString& _password = QString())
+ : type(_type),
+ host(_host),
+ port(_port),
+ username(_username),
+ password(_password)
+ {
+ }
+
+ void toQtNetworkProxy(QNetworkProxy *proxy) const;
+
+ bool operator==(const SeafileProxy& rhs) const;
+ bool operator!=(const SeafileProxy& rhs) const { return !(*this == rhs); };
+
+ static SeafileProxy fromQtNetworkProxy(const QNetworkProxy& proxy);
+ };
+
+ SettingsManager();
+
+ void loadSettings();
+ void setAutoSync(bool);
+
+ bool autoSync() { return auto_sync_; }
+
+ bool notify() { return bubbleNotifycation_; }
+ bool autoStart() { return autoStart_; }
+ unsigned int maxDownloadRatio() { return maxDownloadRatio_; }
+ unsigned int maxUploadRatio() { return maxUploadRatio_; }
+ bool allowInvalidWorktree() { return allow_invalid_worktree_; }
+ bool syncExtraTempFile() { return sync_extra_temp_file_; }
+
+ void getProxy(QNetworkProxy *proxy) const;
+ SeafileProxy getProxy() const { return current_proxy_; };
+
+ void setNotify(bool notify);
+ void setAutoStart(bool autoStart);
+ void setMaxDownloadRatio(unsigned int ratio);
+ void setMaxUploadRatio(unsigned int ratio);
+ void setAllowInvalidWorktree(bool val);
+ void setSyncExtraTempFile(bool sync);
+ void setProxy(const SeafileProxy& proxy);
+
+ bool hideMainWindowWhenStarted();
+ void setHideMainWindowWhenStarted(bool hide);
+
+ bool hideDockIcon();
+ void setHideDockIcon(bool hide);
+
+ // bool defaultLibraryAlreadySetup();
+ // void setDefaultLibraryAlreadySetup();
+
+ void setAllowRepoNotFoundOnServer(bool enabled);
+ bool allowRepoNotFoundOnServer() const { return allow_repo_not_found_on_server_; };
+
+ void setHttpSyncCertVerifyDisabled(bool disabled);
+ bool httpSyncCertVerifyDisabled() const { return verify_http_sync_cert_disabled_; };
+
+ QString getComputerName();
+ void setComputerName(const QString& computerName);
+
+ bool isEnableSyncingWithExistingFolder() const;
+ void setEnableSyncingWithExistingFolder(bool enabled);
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+ QString getLastShibUrl();
+ void setLastShibUrl(const QString& url);
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+ bool getFinderSyncExtension() const;
+ bool getFinderSyncExtensionAvailable() const;
+ void setFinderSyncExtension(bool enabled);
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+#ifdef Q_OS_WIN32
+ void setShellExtensionEnabled(bool enabled);
+ bool shellExtensionEnabled() const { return shell_ext_enabled_; }
+#endif // HAVE_FINDER_SYNC_SUPPORT
+
+public:
+
+ // Remove all settings from system when uninstall
+ static void removeAllSettings();
+ // Write the system proxy information, to be read by seaf-daemon.
+ void writeSystemProxyInfo(const QUrl& url, const QString& file_path);
+
+signals:
+ void autoSyncChanged(bool auto_sync);
+
+private slots:
+ void checkSystemProxy();
+ void onSystemProxyPolled(const QNetworkProxy& proxy);
+
+private:
+ Q_DISABLE_COPY(SettingsManager)
+
+ void loadProxySettings();
+ void writeProxySettingsToDaemon(const SeafileProxy& proxy);
+ void writeProxyDetailsToDaemon(const SeafileProxy& proxy);
+
+ void applyProxySettings();
+
+ bool auto_sync_;
+ bool bubbleNotifycation_;
+ bool autoStart_;
+ bool allow_invalid_worktree_;
+ bool allow_repo_not_found_on_server_;
+ bool sync_extra_temp_file_;
+ unsigned int maxDownloadRatio_;
+ unsigned int maxUploadRatio_;
+ bool verify_http_sync_cert_disabled_;
+ bool shell_ext_enabled_;
+
+ // proxy settings
+ SeafileProxy current_proxy_;
+ QNetworkProxy last_system_proxy_;
+
+ QTimer *check_system_proxy_timer_;
+};
+
+
+// Use to periodically reading the current system proxy.
+class SystemProxyPoller : public QObject, public QRunnable {
+ Q_OBJECT
+public:
+ SystemProxyPoller(const QUrl& url);
+ void run();
+
+signals:
+ void systemProxyPolled(const QNetworkProxy& proxy);
+
+private:
+ QUrl url_;
+};
+
+#endif // SEAFILE_CLIENT_SETTINGS_MANAGER_H
--- /dev/null
+#ifndef SEAFILE_CLIENT_SHIB_HELPER_H
+#define SEAFILE_CLIENT_SHIB_HELPER_H
+
+#include <QWebEnginePage>
+
+class QWebEngineCertificateError;
+class SeafileQWebEnginePage : public QWebEnginePage
+{
+ Q_OBJECT
+public:
+ SeafileQWebEnginePage(QObject *parent = 0);
+
+protected:
+ bool certificateError(
+ const QWebEngineCertificateError &certificateError);
+};
+
+#endif /* SEAFILE_CLIENT_SHIB_HELPER_H */
--- /dev/null
+#include <QtGui>
+#if defined(SEAFILE_USE_WEBKIT)
+ #include <QWebView>
+#else
+ #include <QWebEngineView>
+ #include <QWebEnginePage>
+ #include <QWebEngineProfile>
+ #include <QWebEngineCookieStore>
+ #include "shib-helper.h"
+#endif
+#include <QVBoxLayout>
+#include <QList>
+#include <QLineEdit>
+#include <QSslError>
+#include <QNetworkReply>
+#include <QNetworkCookie>
+
+#include "seafile-applet.h"
+#include "utils/utils.h"
+#include "utils/api-utils.h"
+#include "account-mgr.h"
+#include "network-mgr.h"
+
+#include "shib-login-dialog.h"
+
+namespace {
+
+const char *kSeahubShibCookieName = "seahub_auth";
+
+} // namespace
+
+ShibLoginDialog::ShibLoginDialog(const QUrl& url,
+ const QString& computer_name,
+ QWidget *parent)
+ : QDialog(parent),
+ url_(url),
+ cookie_seen_(false)
+{
+ setWindowTitle(tr("Login with Shibboleth"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ QVBoxLayout *vlayout = new QVBoxLayout();
+ setLayout(vlayout);
+
+ address_text_ = new QLineEdit;
+ address_text_->setObjectName("addressText");
+ address_text_->setText(url.toString());
+ address_text_->setReadOnly(true);
+
+ vlayout->addWidget(address_text_);
+
+#if defined(SEAFILE_USE_WEBKIT)
+ webview_ = new QWebView;
+ CustomCookieJar *jar = new CustomCookieJar(this);
+ QNetworkAccessManager *mgr = webview_->page()->networkAccessManager();
+ NetworkManager::instance()->addWatch(mgr);
+ mgr->setCookieJar(jar);
+
+ connect(mgr, SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError>&)),
+ this, SLOT(sslErrorHandler(QNetworkReply*, const QList<QSslError>&)));
+
+ connect(jar, SIGNAL(newCookieCreated(const QUrl&, const QNetworkCookie&)),
+ this, SLOT(onNewCookieCreated(const QUrl&, const QNetworkCookie&)));
+#else
+ webview_ = new QWebEngineView;
+
+ web_engine_profile_ = new QWebEngineProfile();
+ web_engine_page_ = new QWebEnginePage(web_engine_profile_);
+
+ webview_->setPage(web_engine_page_);
+ QWebEngineCookieStore *jar = webview_->page()->profile()->cookieStore();
+ connect(jar, SIGNAL(cookieAdded(const QNetworkCookie&)),
+ this, SLOT(onWebEngineCookieAdded(const QNetworkCookie&)));
+#endif
+
+ QUrl shib_login_url(url_);
+ QString path = shib_login_url.path();
+ if (!path.endsWith("/")) {
+ path += "/";
+ }
+ path += "shib-login";
+ shib_login_url.setPath(path);
+
+ connect(webview_, SIGNAL(urlChanged(const QUrl&)),
+ this, SLOT(updateAddressBar(const QUrl&)));
+
+ vlayout->addWidget(webview_);
+ webview_->load(::includeQueryParams(
+ shib_login_url, ::getSeafileLoginParams(computer_name, "shib_")));
+}
+
+#if !defined(SEAFILE_USE_WEBKIT)
+ShibLoginDialog::~ShibLoginDialog()
+{
+
+ // The web_engine_page_ object must delete before web_engine_profile.
+ web_engine_page_->deleteLater();
+ web_engine_profile_->deleteLater();
+}
+#endif
+
+void ShibLoginDialog::sslErrorHandler(QNetworkReply* reply,
+ const QList<QSslError> & ssl_errors)
+{
+ reply->ignoreSslErrors();
+}
+
+void ShibLoginDialog::onNewCookieCreated(const QUrl& url, const QNetworkCookie& cookie)
+{
+ if (cookie_seen_) {
+ return;
+ }
+ QString name = cookie.name();
+ QString value = cookie.value();
+ if (url.host() == url_.host() && name == kSeahubShibCookieName) {
+ Account account = parseAccount(value);
+ if (!account.isValid()) {
+ qWarning("wrong account information from server");
+ return;
+ }
+ cookie_seen_ = true;
+ seafApplet->accountManager()->setCurrentAccount(account);
+ accept();
+ }
+}
+
+void ShibLoginDialog::updateAddressBar(const QUrl& url)
+{
+ address_text_->setText(url.toString());
+ // Scroll to the left most.
+ address_text_->home(false);
+}
+
+
+/**
+ * The cookie value is like seahub_shib="foo@test.com@bd8cc1138", where
+ * foo@test.com is username and bd8cc1138 is api token"
+ */
+Account ShibLoginDialog::parseAccount(const QString& cookie_value)
+{
+ QString txt = cookie_value;
+ if (txt.startsWith("\"")) {
+ txt = txt.mid(1, txt.length() - 2);
+ }
+ int pos = txt.lastIndexOf("@");
+ QString email = txt.left(pos);
+ QString token = txt.right(txt.length() - pos - 1);
+ if (email.isEmpty() or token.isEmpty()) {
+ return Account();
+ }
+ return Account(url_, email, token, 0, true);
+}
+
+void ShibLoginDialog::onWebEngineCookieAdded(const QNetworkCookie& cookie)
+{
+ // printf("cookie added: %s = %s\n", cookie.name().data(), cookie.value().data());
+ if (cookie.name() == kSeahubShibCookieName) {
+ onNewCookieCreated(url_, cookie);
+ }
+}
+
+
+CustomCookieJar::CustomCookieJar(QObject *parent)
+ : QNetworkCookieJar(parent)
+{
+}
+
+bool CustomCookieJar::setCookiesFromUrl(const QList<QNetworkCookie>& cookies, const QUrl& url)
+{
+ if (QNetworkCookieJar::setCookiesFromUrl(cookies, url)) {
+ foreach (const QNetworkCookie& cookie, cookies) {
+ emit newCookieCreated(url, cookie);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+#if !defined(SEAFILE_USE_WEBKIT)
+// We create an off-the-record QWebEngineProfile here, because we don't want the
+// cookie to be persisted (the seahub_auth cookie should be cleared each time
+// the shib login dialog is called)
+SeafileQWebEnginePage::SeafileQWebEnginePage(QObject *parent)
+ : QWebEnginePage(new QWebEngineProfile(parent), parent)
+{
+}
+
+bool SeafileQWebEnginePage::certificateError(
+ const QWebEngineCertificateError &certificateError)
+{
+ return true;
+}
+
+#endif
--- /dev/null
+#ifndef SEAFILE_CLIENT_SHIB_LOGIN_DIALOG_H
+#define SEAFILE_CLIENT_SHIB_LOGIN_DIALOG_H
+
+#include <QDialog>
+#include <QUrl>
+#include <QNetworkCookieJar>
+
+#include "account.h"
+
+template<typename T> class QList;
+
+#if defined(SEAFILE_USE_WEBKIT)
+class QWebView;
+#else
+class QWebEngineView;
+class QWebEngineProfile;
+class QWebEnginePage;
+#endif
+
+class QSslError;
+class QNetworkReply;
+class QLineEdit;
+
+/**
+ * Login with Shibboleth SSO.
+ *
+ * This dialog use a webview to let the user login seahub configured with
+ * Shibboleth SSO auth. When the login succeeded, seahub would set the
+ * username and api token in the cookie.
+ */
+class ShibLoginDialog : public QDialog {
+ Q_OBJECT
+public:
+ ShibLoginDialog(const QUrl& url,
+ const QString& computer_name,
+ QWidget *parent=0);
+#if !defined(SEAFILE_USE_WEBKIT)
+~ShibLoginDialog();
+#endif
+
+private slots:
+ void sslErrorHandler(QNetworkReply* reply, const QList<QSslError> & ssl_errors);
+ void onNewCookieCreated(const QUrl& url, const QNetworkCookie& cookie);
+ void onWebEngineCookieAdded(const QNetworkCookie& cookie);
+ void updateAddressBar(const QUrl& url);
+
+private:
+ Account parseAccount(const QString& txt);
+
+#if defined(SEAFILE_USE_WEBKIT)
+ QWebView *webview_;
+#else
+ QWebEngineView *webview_;
+ QWebEngineProfile *web_engine_profile_;
+ QWebEnginePage *web_engine_page_;
+#endif
+ QUrl url_;
+ QLineEdit *address_text_;
+ bool cookie_seen_;
+};
+
+
+/**
+ * Wraps the standard Qt cookie jar to emit a signal when new cookies created.
+ */
+class CustomCookieJar : public QNetworkCookieJar
+{
+ Q_OBJECT
+public:
+ explicit CustomCookieJar(QObject *parent = 0);
+ bool setCookiesFromUrl(const QList<QNetworkCookie>& cookies, const QUrl& url);
+
+signals:
+ void newCookieCreated(const QUrl& url, const QNetworkCookie& cookie);
+};
+
+#endif /* SEAFILE_CLIENT_SHIB_LOGIN_DIALOG_H */
--- /dev/null
+#include <QDir>
+#include <sqlite3.h>
+
+#include "utils/utils.h"
+#include "configurator.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "sync-error-service.h"
+
+namespace {
+
+ void sync_error_entry_from_sqlite3_result(sqlite3_stmt *stmt, LastSyncError::SyncErrorInfo* entry)
+ {
+ entry->id = sqlite3_column_int(stmt, 0);
+ }
+
+} // namespace
+
+
+SINGLETON_IMPL(LastSyncError)
+LastSyncError::LastSyncError()
+{
+ db_ = NULL;
+}
+
+LastSyncError::~LastSyncError()
+{
+ if (db_ != NULL)
+ sqlite3_close(db_);
+}
+
+void LastSyncError::start()
+{
+ const char *errmsg;
+ const char *sql;
+ sqlite3 *db;
+
+ QString db_path = QDir(seafApplet->configurator()->seafileDir()).filePath("sync_error.db");
+ if (sqlite3_open (toCStr(db_path), &db)) {
+ errmsg = sqlite3_errmsg (db);
+ qDebug("failed to open sync error id database %s: %s",
+ toCStr(db_path), errmsg ? errmsg : "no error given");
+
+ seafApplet->errorAndExit(QObject::tr("failed to open sync error id database"));
+ return;
+ }
+
+ sql = "CREATE TABLE IF NOT EXISTS SyncErrorID ("
+ " id integer NOT NULL, "
+ " accountsig VARCHAR(255) NOT NULL, "
+ " PRIMARY KEY (accountsig))";
+ sqlite_query_exec (db, sql);
+
+ db_ = db;
+}
+
+void LastSyncError::saveLatestErrorID(const int id)
+{
+ QString account_sig = seafApplet->accountManager()->currentAccount().getSignature();
+ char *zql = sqlite3_mprintf("REPLACE INTO SyncErrorID(id, accountsig)"
+ " VALUES (%d, %Q)",
+ id,
+ account_sig.toUtf8().data());
+ sqlite_query_exec(db_, zql);
+ sqlite3_free(zql);
+}
+
+bool LastSyncError::collectSyncError(sqlite3_stmt *stmt, void *data)
+{
+ QList<SyncErrorInfo> *list = (QList<SyncErrorInfo> *)data;
+
+ SyncErrorInfo entry;
+ sync_error_entry_from_sqlite3_result(stmt, &entry);
+ list->append(entry);
+ return true;
+}
+
+int LastSyncError::getLastSyncErrorID() {
+ QString account_sig = seafApplet->accountManager()->currentAccount().getSignature();
+ char *sql = sqlite3_mprintf("SELECT *"
+ " FROM SyncErrorID"
+ " WHERE accountsig = %Q",
+ toCStr(account_sig));
+ QList<SyncErrorInfo> list;
+ sqlite_foreach_selected_row(db_, sql, collectSyncError, &list);
+ if (list.size() >= 1) {
+ return list[0].id;
+ }
+ return 0;
+}
+
--- /dev/null
+#ifndef SEAFILE_CLIENT_SYNC_ERROR_H
+#define SEAFILE_CLIENT_SYNC_ERROR_H
+
+#include <QList>
+#include <utility>
+
+#include "utils/singleton.h"
+
+
+struct sqlite3;
+struct sqlite3_stmt;
+
+/**
+ * record the latest sync error id
+ */
+class LastSyncError {
+SINGLETON_DEFINE(LastSyncError)
+public:
+ struct SyncErrorInfo {
+ int id;
+ };
+
+ void start();
+
+ void saveLatestErrorID(const int id);
+ int getLastSyncErrorID();
+
+ QList<LastSyncError::SyncErrorInfo> getAllSyncErrorsInfo();
+
+private:
+ LastSyncError();
+ ~LastSyncError();
+ static bool collectSyncError(sqlite3_stmt *stmt, void *data);
+
+ sqlite3 *db_;
+};
+
+#endif // SEAFILE_CLIENT_SYNC_ERROR_H
--- /dev/null
+#include "traynotificationmanager.h"
+
+TrayNotificationManager::TrayNotificationManager(QObject *parent)
+ : notificationWidgets(new QList<TrayNotificationWidget*>()), QObject(parent)
+{
+ QDesktopWidget* desktopWidget = QApplication::desktop();
+ QRect clientRect = desktopWidget->availableGeometry();
+ m_maxTrayNotificationWidgets = 4;
+ m_width = 320;
+ m_height = 150;
+ m_onScreenCount = 0;
+#if defined(Q_OS_MAC)
+ m_startX = clientRect.width() - m_width;
+ m_startY = 10;
+ m_up = false;
+#endif
+
+#if defined(Q_OS_LINUX)
+ m_startX = clientRect.width() - m_width;
+ m_startY = 10;
+ m_up = false;
+#endif
+
+#if defined(Q_OS_WIN32)
+ m_startX = clientRect.width() - m_width;
+ m_startY = clientRect.height() - m_height;
+ m_up = true;
+#endif
+
+ m_deltaX = 0;
+ m_deltaY = 0;
+}
+
+TrayNotificationManager::~TrayNotificationManager()
+{
+ // call delete and remove all remaining widgets in notificationWidgets
+ clear();
+
+ // then delete qlist notificationWidgets
+ delete notificationWidgets;
+}
+
+void TrayNotificationManager::setMaxTrayNotificationWidgets(int max)
+{
+ this->m_maxTrayNotificationWidgets = max;
+}
+
+void TrayNotificationManager::append(TrayNotificationWidget* widget)
+{
+ connect(widget, SIGNAL(deleted()), this, SLOT(removeWidget()));
+ if (notificationWidgets->count() < m_maxTrayNotificationWidgets)
+ {
+ if (!notificationWidgets->empty())
+ {
+ if(m_up)
+ m_deltaY += -100;
+ else
+ m_deltaY += 100;
+ } else
+ {
+ m_deltaY = 0;
+ }
+ }
+ else
+ {
+ m_deltaY = 0;
+ }
+
+ widget->setGeometry(m_startX + m_deltaX, m_startY + m_deltaY, widget->size().width(), widget->size().height());
+ notificationWidgets->append(widget);
+}
+
+void TrayNotificationManager::removeWidget()
+{
+ TrayNotificationWidget *widget = qobject_cast<TrayNotificationWidget*>(sender());
+
+ if (widget == NULL)
+ {
+ return;
+ }
+
+ int i = notificationWidgets->indexOf(widget);
+
+ if (i != -1)
+ {
+ notificationWidgets->takeAt(i)->deleteLater();
+ }
+}
+
+void TrayNotificationManager::clear()
+{
+ // call operator delete on all items in list notificationWidgets
+ qDeleteAll(*notificationWidgets);
+
+ // remove all items from it since qDeleteAll don't do it for us
+ notificationWidgets->clear();
+}
--- /dev/null
+#ifndef TRAYNOTIFICATIONMANAGER_H
+#define TRAYNOTIFICATIONMANAGER_H
+
+#include <QtCore>
+#include "traynotificationwidget.h"
+
+class TrayNotificationManager : public QObject
+{
+ Q_OBJECT
+public:
+ TrayNotificationManager(QObject *parent);
+ ~TrayNotificationManager();
+ void append(TrayNotificationWidget *widget);
+ void clear();
+ void setMaxTrayNotificationWidgets(int max);
+
+private slots:
+ void removeWidget();
+
+private:
+ QList<TrayNotificationWidget*>* notificationWidgets;
+ int m_deltaX;
+ int m_deltaY;
+ int m_startX;
+ int m_startY;
+ int m_width;
+ int m_height;
+ bool m_up;
+ int m_onScreenCount;
+ int m_maxTrayNotificationWidgets;
+};
+
+#endif // TRAYNOTIFICATIONMANAGER_H
--- /dev/null
+#include "traynotificationwidget.h"
+
+TrayNotificationWidget::TrayNotificationWidget(QPixmap pixmapIcon, QString headerText, QString messageText) : QWidget(0)
+{
+ setWindowFlags(
+ #if defined(Q_OS_MAC)
+ Qt::SubWindow | // This type flag is the second point
+ #else
+ Qt::Tool |
+ #endif
+ Qt::FramelessWindowHint |
+ Qt::WindowSystemMenuHint |
+ Qt::WindowStaysOnTopHint
+ );
+ setAttribute(Qt::WA_NoSystemBackground, true);
+ // set the parent widget's background to translucent
+ setAttribute(Qt::WA_TranslucentBackground, true);
+
+ //setAttribute(Qt::WA_ShowWithoutActivating, true);
+ setFixedWidth(310);
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+ // create a display widget for displaying child widgets
+ QWidget* displayWidget = new QWidget;
+ displayWidget->setStyleSheet(".QWidget { background-color: rgba(0, 0, 0, 75%); border-width: 1px; border-style: solid; border-radius: 10px; border-color: #555555; } .QWidget:hover { background-color: rgba(68, 68, 68, 75%); border-width: 2px; border-style: solid; border-radius: 10px; border-color: #ffffff; }");
+ displayWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
+
+ QLabel* icon = new QLabel;
+ icon->setPixmap(pixmapIcon);
+ icon->setMaximumSize(32, 32);
+
+ QLabel* header = new QLabel;
+ header->setStyleSheet("QLabel { color: #ffffff; font-weight: bold; font-size: 12px; }");
+ header->setText(headerText);
+ header->setFixedWidth(200);
+ header->setWordWrap(true);
+ header->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+
+ QTextEdit *message = new QTextEdit;
+ message->setReadOnly(true);
+ message->setFrameStyle(QFrame::NoFrame);
+ message->setLineWrapMode(QTextEdit::WidgetWidth);
+ message->setWordWrapMode(QTextOption::WrapAnywhere);
+
+ QPalette pal = palette();
+ pal.setColor(QPalette::Base, Qt::transparent);
+ message->setPalette(pal);
+ message->setStyleSheet("QTextEdit { color: #ffffff; font-size: 10px; }");
+ message->setText(messageText);
+ message->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ QVBoxLayout* vl = new QVBoxLayout;
+ vl->addWidget(header);
+ vl->addWidget(message);
+
+ QHBoxLayout* displayMainLayout = new QHBoxLayout;
+ displayMainLayout->addWidget(icon);
+ displayMainLayout->addLayout(vl);
+
+ displayWidget->setLayout(displayMainLayout);
+
+ QHBoxLayout* containerLayout = new QHBoxLayout;
+ containerLayout->addWidget(displayWidget);
+ setLayout(containerLayout);
+
+ show();
+ resize(this->size().width(), (int)((message->document()->size().height() + header->height()) +70));
+
+ timeout = new QTimer(this);
+ connect(timeout, SIGNAL(timeout()), this, SLOT(fadeOut()));
+ timeout->start(3000);
+}
+
+void TrayNotificationWidget::fadeOut()
+{
+ timeout->stop();
+
+ this->hide();
+ emit deleted();
+}
--- /dev/null
+#ifndef TRAYNOTIFICATIONWIDGET_H
+#define TRAYNOTIFICATIONWIDGET_H
+
+#include <QWidget>
+
+#include <QtGlobal>
+
+#include <QtWidgets>
+
+class TrayNotificationWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit TrayNotificationWidget(QPixmap pixmapIcon, QString headerText, QString messageText);
+
+private:
+ QTimer* timeout;
+signals:
+ void deleted();
+
+private slots:
+ void fadeOut();
+};
+
+#endif // TRAYNOTIFICATIONWIDGET_H
--- /dev/null
+#include <QtWidgets>
+
+#include "seafile-applet.h"
+#include "utils/utils.h"
+
+#include "about-dialog.h"
+
+#ifdef HAVE_SPARKLE_SUPPORT
+#include "auto-update-service.h"
+#endif
+
+namespace {
+
+} // namespace
+
+AboutDialog::AboutDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+ setWindowTitle(tr("About %1").arg(getBrand()));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) |
+ Qt::WindowStaysOnTopHint);
+
+ version_text_ = tr("<h2>%1 Client %2</h2>")
+ .arg(getBrand())
+ .arg(STRINGIZE(SEAFILE_CLIENT_VERSION))
+#ifdef SEAFILE_CLIENT_REVISION
+ .append(tr("<h5> REV %1 </h5>"))
+ .arg(STRINGIZE(SEAFILE_CLIENT_REVISION))
+#endif
+ ;
+ mVersionText->setText(version_text_);
+
+ connect(mOKBtn, SIGNAL(clicked()), this, SLOT(close()));
+
+ mCheckUpdateBtn->setVisible(false);
+#ifdef HAVE_SPARKLE_SUPPORT
+ if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+ mCheckUpdateBtn->setVisible(true);
+ connect(mCheckUpdateBtn, SIGNAL(clicked()), this, SLOT(checkUpdate()));
+ }
+#endif
+}
+
+#ifdef HAVE_SPARKLE_SUPPORT
+void AboutDialog::checkUpdate()
+{
+ AutoUpdateService::instance()->checkUpdate();
+ close();
+}
+#endif
--- /dev/null
+#ifndef SEAFILE_CLIENT_ABOUT_DIALOG_H
+#define SEAFILE_CLIENT_ABOUT_DIALOG_H
+
+#include <QDialog>
+#include "ui_about-dialog.h"
+
+class AutoUpdateService;
+
+class AboutDialog : public QDialog,
+ public Ui::AboutDialog
+{
+ Q_OBJECT
+public:
+ AboutDialog(QWidget *parent=0);
+
+#ifdef HAVE_SPARKLE_SUPPORT
+private slots:
+ void checkUpdate();
+#endif
+
+private:
+ Q_DISABLE_COPY(AboutDialog)
+
+ QString version_text_;
+};
+
+#endif // SEAFILE_CLIENT_ABOUT_DIALOG_H
--- /dev/null
+#include <QtGui>
+
+#include "settings-mgr.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "account-settings-dialog.h"
+
+namespace {
+
+} // namespace
+
+AccountSettingsDialog::AccountSettingsDialog(const Account& account, QWidget *parent)
+ : QDialog(parent),
+ account_(account)
+{
+ setupUi(this);
+ setWindowTitle(tr("Account Settings"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ mServerAddr->setText(account_.serverUrl.toString());
+ mUsername->setText(account_.username);
+ mUsername->setEnabled(false);
+
+ #if defined(Q_OS_MAC)
+ layout()->setContentsMargins(9, 9, 9, 9);
+ layout()->setSpacing(6);
+ formLayout->setSpacing(6);
+ formLayout->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
+ formLayout->setLabelAlignment(Qt::AlignLeft);
+ formLayout->setFormAlignment(Qt::AlignLeft);
+ horizontalLayout->setSpacing(6);
+ #endif
+
+ connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onSubmitBtnClicked()));
+
+ // const QRect screen = QApplication::desktop()->screenGeometry();
+ // move(screen.center() - this->rect().center());
+}
+
+void AccountSettingsDialog::showWarning(const QString& msg)
+{
+ seafApplet->warningBox(msg, this);
+}
+
+bool AccountSettingsDialog::validateInputs()
+{
+ QString server_addr = mServerAddr->text().trimmed();
+ QUrl url;
+
+ if (server_addr.size() == 0) {
+ showWarning(tr("Please enter the server address"));
+ return false;
+ } else {
+ if (!server_addr.startsWith("http://") && !server_addr.startsWith("https://")) {
+ showWarning(tr("%1 is not a valid server address").arg(server_addr));
+ return false;
+ }
+
+ url = QUrl(server_addr, QUrl::StrictMode);
+ if (!url.isValid()) {
+ showWarning(tr("%1 is not a valid server address").arg(server_addr));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void AccountSettingsDialog::onSubmitBtnClicked()
+{
+ if (!validateInputs()) {
+ return;
+ }
+
+ QString url = mServerAddr->text().trimmed();
+ if (url != account_.serverUrl.toString()) {
+ Account new_account(account_);
+ new_account.serverUrl = url;
+ if (seafApplet->accountManager()->replaceAccount(account_,
+ new_account) < 0) {
+ showWarning(tr("Failed to save account information"));
+ return;
+ }
+ QString error;
+ QUrl new_server_url = new_account.serverUrl;
+ new_server_url.setPath("/");
+
+ QUrl url = account_.serverUrl;
+ url.setPath("/");
+
+ if (seafApplet->rpcClient()->updateReposServerHost(url,
+ new_account.serverUrl.host(), new_server_url.toString(), &error) < 0) {
+ showWarning(tr("Failed to save the changes: %1").arg(error));
+ return;
+ }
+ }
+
+ seafApplet->messageBox(tr("Successfully updated current account information"), this);
+ accept();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_ACCOUNT_SETTINGS_H
+#define SEAFILE_CLIENT_ACCOUNT_SETTINGS_H
+
+#include <QDialog>
+#include "ui_account-settings-dialog.h"
+
+#include <QUrl>
+#include <QString>
+
+#include "account.h"
+
+class AccountSettingsDialog : public QDialog,
+ public Ui::AccountSettingsDialog
+{
+ Q_OBJECT
+public:
+ AccountSettingsDialog(const Account& account, QWidget *parent=0);
+
+private slots:
+ void onSubmitBtnClicked();
+
+private:
+ Q_DISABLE_COPY(AccountSettingsDialog);
+ bool validateInputs();
+ void showWarning(const QString& msg);
+
+ Account account_;
+};
+
+#endif // SEAFILE_CLIENT_ACCOUNT_SETTINGS_H
--- /dev/null
+#include <QMenu>
+#include <QAction>
+#include <QToolButton>
+#include <QScopedPointer>
+#include <QPainter>
+#include <QStringList>
+#include <QDesktopServices>
+#include <QMouseEvent>
+#include <QUrl>
+#include <QUrlQuery>
+#include <QThreadPool>
+
+#include "account.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "login-dialog.h"
+#include "settings-mgr.h"
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+#include "shib/shib-login-dialog.h"
+#endif // HAVE_SHIBBOLETH_SUPPORT
+#include "account-settings-dialog.h"
+#include "rpc/rpc-client.h"
+#include "main-window.h"
+#include "init-vdrive-dialog.h"
+#include "auto-login-service.h"
+#include "avatar-service.h"
+#include "utils/paint-utils.h"
+#include "filebrowser/file-browser-manager.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "filebrowser/auto-update-mgr.h"
+#include "repo-service.h"
+
+#include "account-view.h"
+namespace {
+
+} // namespace
+
+AccountView::AccountView(QWidget *parent)
+ : QWidget(parent)
+{
+ setupUi(this);
+
+ // Init account drop down menu
+ account_menu_ = new QMenu;
+ mAccountBtn->setMenu(account_menu_);
+ mAccountBtn->setPopupMode(QToolButton::InstantPopup);
+ mAccountBtn->setFixedSize(QSize(AvatarService::kAvatarSize, AvatarService::kAvatarSize));
+
+ onAccountChanged();
+
+ connect(AvatarService::instance(), SIGNAL(avatarUpdated(const QString&, const QImage&)),
+ this, SLOT(updateAvatar()));
+
+ mAccountBtn->setCursor(Qt::PointingHandCursor);
+ mAccountBtn->installEventFilter(this);
+ account_menu_->installEventFilter(this);
+
+ connect(seafApplet->accountManager(), SIGNAL(requireAddAccount()),
+ this, SLOT(showAddAccountDialog()));
+ connect(mServerAddr, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(visitServerInBrowser(const QString&)));
+
+ // Must get the pixmap from QIcon because QIcon would load the 2x version
+ // automatically.
+ mRefreshLabel->setPixmap(QIcon(":/images/toolbar/refresh-new.png").pixmap(20));
+ mRefreshLabel->installEventFilter(this);
+}
+
+void AccountView::showAddAccountDialog()
+{
+ LoginDialog dialog(this);
+ // Show InitVirtualDriveDialog for the first account added
+ AccountManager *account_mgr = seafApplet->accountManager();
+ if (dialog.exec() == QDialog::Accepted
+ && account_mgr->accounts().size() == 1) {
+
+ InitVirtualDriveDialog dialog(account_mgr->currentAccount(), seafApplet->mainWindow());
+#if defined(Q_OS_WIN32)
+ dialog.exec();
+#endif
+ }
+}
+
+void AccountView::deleteAccount()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ if (!action)
+ return;
+ Account account = qvariant_cast<Account>(action->data());
+
+ // QString question = tr("Are you sure to remove account from \"%1\"?<br>"
+ // "<b>Warning: All libraries of this account would be unsynced!</b>").arg(account.serverUrl.toString());
+
+ QString question = tr("Are you sure you want to remove account %1?<br><br>"
+ "The account will be removed locally. All syncing "
+ "configuration will be removed too. The account at "
+ "the server will not be affected.")
+ .arg(account.username);
+
+ if (seafApplet->yesOrNoBox(question, this, false)) {
+ FileBrowserManager::getInstance()->closeAllDialogByAccount(account);
+ QString error;
+ QUrl server_url = account.serverUrl;
+ server_url.setPath("/");
+ if (seafApplet->rpcClient()->unsyncReposByAccount(server_url,
+ account.username,
+ &error) < 0) {
+
+ seafApplet->warningBox(
+ tr("Failed to unsync libraries of this account: %1").arg(error),
+ this);
+ }
+
+ seafApplet->accountManager()->removeAccount(account);
+ }
+}
+
+void AccountView::editAccountSettings()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ if (!action)
+ return;
+ Account account = qvariant_cast<Account>(action->data());
+
+ AccountSettingsDialog dialog(account, this);
+
+ dialog.exec();
+}
+
+void AccountView::updateAccountInfoDisplay()
+{
+ if (seafApplet->accountManager()->hasAccount()) {
+ const Account account = seafApplet->accountManager()->currentAccount();
+ if (!account.accountInfo.name.isEmpty()) {
+ mEmail->setText(account.accountInfo.name);
+ } else {
+ mEmail->setText(account.username);
+ }
+ // mServerAddr->setOpenExternalLinks(true);
+ mServerAddr->setToolTip(tr("click to open the website"));
+
+ QString host = account.serverUrl.host();
+ QString href = account.serverUrl.toString();
+ QString text = QString("<a style="
+ "\"color:#A4A4A4; text-decoration: none;\" "
+ "href=\"%1\">%2</a>").arg(href).arg(host);
+
+ mServerAddr->setText(account.isPro() ? QString("%1 <small>%2<small>").arg(text).arg(tr("pro version")) : text);
+ } else {
+ mEmail->setText(tr("No account"));
+ mServerAddr->setText(QString());
+ }
+
+ updateAvatar();
+}
+
+/**
+ * Update the account menu when accounts changed
+ */
+void AccountView::onAccountChanged()
+{
+ const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+
+ // Remove all menu items
+ account_menu_->clear();
+
+ if (!accounts.empty()) {
+ for (size_t i = 0, n = accounts.size(); i < n; i++) {
+ const Account &account = accounts[i];
+ QString text_name = account.accountInfo.name.isEmpty() ?
+ account.username : account.accountInfo.name;
+ QString text = text_name + " (" + account.serverUrl.host() + ")";
+ if (!account.isValid()) {
+ text += ", " + tr("not logged in");
+ }
+ QMenu *submenu = new QMenu(text, account_menu_);
+ if (i == 0) {
+ submenu->setIcon(QIcon(":/images/account-checked.png"));
+ } else {
+ submenu->setIcon(QIcon(":/images/account-else.png"));
+ }
+
+ QAction *submenu_action = submenu->menuAction();
+ submenu_action->setData(QVariant::fromValue(account));
+ connect(submenu_action, SIGNAL(triggered()), this, SLOT(onAccountItemClicked()));
+
+ QAction *action = new QAction(tr("Choose"), submenu);
+ action->setIcon(QIcon(":/images/account-checked.png"));
+ action->setIconVisibleInMenu(true);
+ action->setData(QVariant::fromValue(account));
+ connect(action, SIGNAL(triggered()), this, SLOT(onAccountItemClicked()));
+
+ submenu->addAction(action);
+ submenu->setDefaultAction(action);
+
+ QAction *account_settings_action = new QAction(tr("Account settings"), this);
+ account_settings_action->setIcon(QIcon(":/images/account-settings.png"));
+ account_settings_action->setIconVisibleInMenu(true);
+ account_settings_action->setData(QVariant::fromValue(account));
+ connect(account_settings_action, SIGNAL(triggered()), this, SLOT(editAccountSettings()));
+ submenu->addAction(account_settings_action);
+
+ QAction *toggle_action = new QAction(this);
+ toggle_action->setIcon(QIcon(":/images/logout.png"));
+ toggle_action->setIconVisibleInMenu(true);
+ toggle_action->setData(QVariant::fromValue(account));
+ connect(toggle_action, SIGNAL(triggered()), this, SLOT(toggleAccount()));
+ if (account.isValid())
+ toggle_action->setText(tr("Logout"));
+ else
+ toggle_action->setText(tr("Login"));
+ submenu->addAction(toggle_action);
+
+ QAction *delete_account_action = new QAction(tr("Delete"), this);
+ delete_account_action->setIcon(QIcon(":/images/delete-account.png"));
+ delete_account_action->setIconVisibleInMenu(true);
+ delete_account_action->setData(QVariant::fromValue(account));
+ connect(delete_account_action, SIGNAL(triggered()), this, SLOT(deleteAccount()));
+ submenu->addAction(delete_account_action);
+
+ account_menu_->addMenu(submenu);
+ }
+
+ account_menu_->addSeparator();
+ }
+
+ add_account_action_ = new QAction(tr("Add an account"), this);
+ add_account_action_->setIcon(QIcon(":/images/add-account.png"));
+ add_account_action_->setIconVisibleInMenu(true);
+ connect(add_account_action_, SIGNAL(triggered()), this, SLOT(showAddAccountDialog()));
+ account_menu_->addAction(add_account_action_);
+
+ updateAccountInfoDisplay();
+}
+
+QAction* AccountView::makeAccountAction(const Account& account)
+{
+ QString text = account.username + "(" + account.serverUrl.host() + ")";
+ if (!account.isValid()) {
+ text += ", " + tr("not logged in");
+ }
+ QAction *action = new QAction(text, account_menu_);
+ action->setData(QVariant::fromValue(account));
+ // action->setCheckable(true);
+ // QMenu won't display tooltip for menu item
+ // action->setToolTip(account.serverUrl.host());
+
+ connect(action, SIGNAL(triggered()), this, SLOT(onAccountItemClicked()));
+
+ return action;
+}
+
+// Switch to the clicked account in the account menu
+void AccountView::onAccountItemClicked()
+{
+ QAction *action = (QAction *)(sender());
+ Account account = qvariant_cast<Account>(action->data());
+
+ if (!account.isValid()) {
+ seafApplet->accountManager()->reloginAccount(account);
+ } else {
+ seafApplet->accountManager()->setCurrentAccount(account);
+ }
+}
+
+void AccountView::updateAvatar()
+{
+ mAccountBtn->setIconSize(QSize(AvatarService::kAvatarSize, AvatarService::kAvatarSize));
+ const Account account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ mAccountBtn->setIcon(QIcon(":/images/account.png"));
+ return;
+ }
+
+ AvatarService *service = AvatarService::instance();
+ QIcon avatar = QPixmap::fromImage(service->getAvatar(account.username));
+ mAccountBtn->setIcon(QIcon(avatar));
+}
+
+bool AccountView::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == account_menu_ && event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *ev = (QMouseEvent*)event;
+ QAction *action = account_menu_->actionAt(ev->pos());
+ if (action) {
+ action->trigger();
+ }
+ }
+ if (obj == mAccountBtn && event->type() == QEvent::Paint) {
+ QRect rect(0, 0, AvatarService::kAvatarSize, AvatarService::kAvatarSize);
+ QPainter painter(mAccountBtn);
+ painter.setRenderHint(QPainter::Antialiasing);
+ painter.setRenderHint(QPainter::HighQualityAntialiasing);
+
+ // get the device pixel radio from current painter device
+ double scale_factor = globalDevicePixelRatio();
+
+ QPixmap image(mAccountBtn->icon().pixmap(rect.size()).scaled(scale_factor * rect.size()));
+ QRect actualRect(QPoint(0, 0),
+ QSize(AvatarService::kAvatarSize * scale_factor,
+ AvatarService::kAvatarSize * scale_factor));
+
+ QImage masked_image(actualRect.size(),
+ QImage::Format_ARGB32_Premultiplied);
+ masked_image.fill(Qt::transparent);
+ QPainter mask_painter;
+ mask_painter.begin(&masked_image);
+ mask_painter.setRenderHint(QPainter::Antialiasing);
+ mask_painter.setRenderHint(QPainter::HighQualityAntialiasing);
+ mask_painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ mask_painter.setPen(Qt::NoPen);
+ mask_painter.setBrush(Qt::white);
+ mask_painter.drawEllipse(actualRect);
+ mask_painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ mask_painter.drawPixmap(actualRect, image);
+ mask_painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
+ mask_painter.fillRect(actualRect, Qt::transparent);
+ mask_painter.end();
+ masked_image.setDevicePixelRatio(scale_factor);
+
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ painter.drawImage(QPoint(0,0), masked_image);
+ return true;
+ }
+ if (obj == mRefreshLabel) {
+ if (event->type() == QEvent::MouseButtonPress) {
+ emit refresh();
+ return true;
+ } else if (event->type() == QEvent::Enter) {
+ mRefreshLabel->setPixmap(QIcon(":/images/toolbar/refresh-orange.png").pixmap(20));
+ return true;
+ } else if (event->type() == QEvent::Leave) {
+ mRefreshLabel->setPixmap(QIcon(":/images/toolbar/refresh-new.png").pixmap(20));
+ return true;
+ }
+ }
+ return QObject::eventFilter(obj, event);
+}
+
+/**
+ * Only remove the api token of the account. The accout would still be shown
+ * in the account list.
+ */
+void AccountView::toggleAccount()
+{
+ QAction *action = qobject_cast<QAction*>(sender());
+ if (!action)
+ return;
+ Account account = qvariant_cast<Account>(action->data());
+ if (!account.isValid()) {
+ seafApplet->accountManager()->reloginAccount(account);
+ return;
+ }
+
+ qWarning("Logging out current account %s", account.username.toUtf8().data());
+ AutoUpdateManager::instance()->cleanCachedFile();
+
+ // logout Account
+ FileBrowserManager::getInstance()->closeAllDialogByAccount(account);
+ seafApplet->accountManager()->logoutDevice(account);
+}
+
+void AccountView::visitServerInBrowser(const QString& link)
+{
+ AutoLoginService::instance()->startAutoLogin("/");
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_ACCOUNT_VIEW_H
+#define SEAFILE_CLIENT_UI_ACCOUNT_VIEW_H
+
+#include <QWidget>
+
+#include "utils/singleton.h"
+#include "ui_account-view.h"
+
+class Account;
+class QAction;
+class QMenu;
+class ApiError;
+class QLabel;
+
+/*
+ * The account information area, right below the header
+ */
+class AccountView : public QWidget,
+ public Ui::AccountView
+{
+ Q_OBJECT
+public:
+ AccountView(QWidget *parent=0);
+
+public slots:
+ void onAccountChanged();
+ void showAddAccountDialog();
+ void deleteAccount();
+ void editAccountSettings();
+ void onAccountItemClicked();
+ void updateAccountInfoDisplay();
+
+private slots:
+ void updateAvatar();
+ void toggleAccount();
+ void visitServerInBrowser(const QString& link);
+
+private:
+ Q_DISABLE_COPY(AccountView)
+
+ QAction *makeAccountAction(const Account& account);
+ bool eventFilter(QObject *obj, QEvent *event);
+
+ // Account operations
+ QAction *add_account_action_;
+ QAction *account_settings_action_;
+ QMenu *account_menu_;
+
+signals:
+ void refresh();
+};
+
+#endif // SEAFILE_CLIENT_UI_ACCOUNT_VIEW_H
--- /dev/null
+#include <cstdio>
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QIcon>
+#include <QStackedWidget>
+#include <QModelIndex>
+#include <QLabel>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "events-list-view.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "events-service.h"
+#include "avatar-service.h"
+#include "api/api-error.h"
+#include "utils/utils.h"
+
+#include "activities-tab.h"
+
+namespace {
+
+//const int kRefreshInterval = 1000 * 60 * 5; // 5 min
+const char *kLoadingFailedLabelName = "loadingFailedText";
+//const char *kEmptyViewLabelName = "emptyText";
+//const char *kAuthHeader = "Authorization";
+//const char *kActivitiesUrl = "/api2/html/events/";
+
+enum {
+ INDEX_LOADING_VIEW = 0,
+ INDEX_LOADING_FAILED_VIEW,
+ INDEX_LOGOUT_VIEW,
+ INDEX_EVENTS_VIEW,
+};
+
+
+}
+
+
+ActivitiesTab::ActivitiesTab(QWidget *parent)
+ : TabView(parent)
+{
+ createEventsView();
+ createLoadingView();
+ createLoadingFailedView();
+
+ //createLogoutView
+ logout_view_ = new LogoutView;
+ static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+ mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+ mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+ mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+ mStack->insertWidget(INDEX_EVENTS_VIEW, events_container_view_);
+
+ connect(EventsService::instance(), SIGNAL(refreshSuccess(const std::vector<SeafEvent>&, bool, bool)),
+ this, SLOT(refreshEvents(const std::vector<SeafEvent>&, bool, bool)));
+ connect(EventsService::instance(), SIGNAL(refreshFailed(const ApiError&)),
+ this, SLOT(refreshFailed(const ApiError&)));
+
+ connect(AvatarService::instance(), SIGNAL(avatarUpdated(const QString&, const QImage&)),
+ events_list_model_, SLOT(onAvatarUpdated(const QString&, const QImage&)));
+
+ refresh();
+}
+
+void ActivitiesTab::showEvent(QShowEvent *event)
+{
+ TabView::showEvent(event);
+ if (mStack->currentIndex() == INDEX_EVENTS_VIEW) {
+ events_list_view_->update();
+ }
+}
+
+void ActivitiesTab::loadMoreEvents()
+{
+ EventsService::instance()->loadMore();
+}
+
+void ActivitiesTab::refreshEvents(const std::vector<SeafEvent>& events,
+ bool is_loading_more,
+ bool has_more)
+{
+ events_list_model_->removeRow(
+ events_list_model_->loadMoreIndex().row());
+
+ mStack->setCurrentIndex(INDEX_EVENTS_VIEW);
+
+ // XXX: "load more events" for now
+ const QModelIndex first =
+ events_list_model_->updateEvents(events, is_loading_more, has_more);
+ if (first.isValid()) {
+ events_list_view_->scrollTo(first);
+ }
+
+ if (has_more) {
+ load_more_btn_ = new LoadMoreButton;
+ connect(load_more_btn_, SIGNAL(clicked()),
+ this, SLOT(loadMoreEvents()));
+ events_list_view_->setIndexWidget(
+ events_list_model_->loadMoreIndex(), load_more_btn_);
+ }
+}
+
+void ActivitiesTab::refresh()
+{
+ if (!seafApplet->accountManager()->hasAccount() ||
+ !seafApplet->accountManager()->accounts().front().isValid()) {
+ mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+ return;
+ }
+ showLoadingView();
+
+ EventsService::instance()->refresh(true);
+}
+
+void ActivitiesTab::createEventsView()
+{
+ events_container_view_ = new QWidget;
+ events_container_view_->setObjectName("EventsContainerView");
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ events_container_view_->setLayout(layout);
+
+ events_list_view_ = new EventsListView;
+ layout->addWidget(events_list_view_);
+
+ events_list_model_ = new EventsListModel;
+ events_list_view_->setModel(events_list_model_);
+}
+
+void ActivitiesTab::createLoadingView()
+{
+ loading_view_ = new LoadingView;
+ static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void ActivitiesTab::createLoadingFailedView()
+{
+ loading_failed_view_ = new QWidget(this);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ loading_failed_view_->setLayout(layout);
+
+ loading_failed_text_ = new QLabel;
+ loading_failed_text_->setObjectName(kLoadingFailedLabelName);
+ loading_failed_text_->setAlignment(Qt::AlignCenter);
+
+ connect(loading_failed_text_, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(refresh()));
+
+ layout->addWidget(loading_failed_text_);
+}
+
+void ActivitiesTab::showLoadingView()
+{
+ mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void ActivitiesTab::refreshFailed(const ApiError& error)
+{
+ QString text;
+ if (error.type() == ApiError::HTTP_ERROR
+ && error.httpErrorCode() == 404) {
+ text = tr("File Activities are only supported in %1 Server Professional Edition.").arg(getBrand());
+ } else {
+ QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+ text = tr("Failed to get actvities information. "
+ "Please %1").arg(link);
+ }
+
+ loading_failed_text_->setText(text);
+
+ mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+}
+
+void ActivitiesTab::startRefresh()
+{
+ AccountManager *mgr = seafApplet->accountManager();
+ bool has_pro_account = mgr->hasAccount() && mgr->accounts().front().isPro();
+ if (has_pro_account)
+ EventsService::instance()->start();
+}
+
+void ActivitiesTab::stopRefresh()
+{
+ EventsService::instance()->stop();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_ACTIVITIES_TAB_H
+#define SEAFILE_CLIENT_UI_ACTIVITIES_TAB_H
+
+#include <vector>
+#include <QList>
+
+#include "tab-view.h"
+
+class QSslError;
+class QUrl;
+class QNetworkRequest;
+class QNetworkReply;
+class LoadMoreButton;
+class QLabel;
+class QShowEvent;
+
+class SeafEvent;
+class Account;
+class ApiError;
+class EventsListView;
+class EventsListModel;
+
+/**
+ * The activities tab
+ */
+class ActivitiesTab : public TabView {
+ Q_OBJECT
+public:
+ explicit ActivitiesTab(QWidget *parent=0);
+
+public slots:
+ void refresh();
+
+protected:
+ void startRefresh();
+ void stopRefresh();
+ virtual void showEvent(QShowEvent *event);
+
+private slots:
+ void refreshEvents(const std::vector<SeafEvent>& events,
+ bool is_loading_more,
+ bool has_more);
+ void refreshFailed(const ApiError& error);
+ void loadMoreEvents();
+
+private:
+ void createEventsView();
+ void createLoadingView();
+ void createLoadingFailedView();
+ void showLoadingView();
+ void loadPage(const Account& account);
+
+ QWidget *loading_view_;
+ QWidget *loading_failed_view_;
+ QWidget *logout_view_;
+
+ QWidget *events_container_view_;
+ EventsListView *events_list_view_;
+ EventsListModel *events_list_model_;
+ QWidget *events_loading_view_;
+ LoadMoreButton *load_more_btn_;
+
+ QLabel *loading_failed_text_;
+};
+
+#endif // SEAFILE_CLIENT_UI_ACTIVITIES_TAB_H
--- /dev/null
+#include <QtGui>
+#include <QTimer>
+#include <QLabel>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QProgressBar>
+#include <QPushButton>
+
+#include "filebrowser/seaf-dirent.h"
+#include "filebrowser/data-mgr.h"
+#include "seafile-applet.h"
+
+#include "check-repo-root-perm-dialog.h"
+
+CheckRepoRootDirPermDialog::CheckRepoRootDirPermDialog(const Account &account,
+ const ServerRepo& repo,
+ const QString& local_path,
+ QWidget *parent)
+ : QProgressDialog(parent),
+ account_(account),
+ repo_(repo),
+ local_path_(local_path),
+ has_write_perm_(false)
+{
+ // Here we use the data manager class to fetch the dir instead of doing it
+ // directly, because DataManager class would make use of the shared
+ // in-memory dirents cache.
+ data_mgr_ = seafApplet->dataManager();
+
+ setWindowModality(Qt::WindowModal);
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ QVBoxLayout *layout_ = new QVBoxLayout;
+ progress_bar_ = new QProgressBar;
+ description_label_ = new QLabel;
+
+ layout_->addWidget(description_label_);
+ layout_->addWidget(progress_bar_);
+
+ QHBoxLayout *hlayout_ = new QHBoxLayout;
+ more_details_label_ = new QLabel;
+ more_details_label_->setText(tr("Checking Permission"));
+ QPushButton *cancel_button_ = new QPushButton(tr("Cancel"));
+ QWidget *spacer = new QWidget;
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ hlayout_->addWidget(more_details_label_);
+ hlayout_->addWidget(spacer);
+ hlayout_->addWidget(cancel_button_);
+ hlayout_->setContentsMargins(-1, 0, -1, 6);
+ layout_->setContentsMargins(-1, 0, -1, 6);
+ layout_->addLayout(hlayout_);
+
+ setLayout(layout_);
+ setLabel(description_label_);
+ setBar(progress_bar_);
+ setCancelButton(cancel_button_);
+
+ data_mgr_notify_ = new DataManagerNotify(repo_.id);
+ connect(data_mgr_notify_, SIGNAL(getDirentsSuccess(bool, const QList<SeafDirent>&)),
+ this, SLOT(onGetDirentsSuccess(bool)));
+ connect(data_mgr_notify_, SIGNAL(getDirentsFailed(const ApiError&)),
+ this, SLOT(onGetDirentsFailed()));
+
+ setValue(minimum());
+ QTimer::singleShot(0, this, SLOT(checkPerm()));
+}
+
+CheckRepoRootDirPermDialog::~CheckRepoRootDirPermDialog()
+{
+ // printf ("destructor called for CheckRepoRootDirPermDialog\n");
+ delete data_mgr_notify_;
+}
+
+void CheckRepoRootDirPermDialog::checkPerm()
+{
+ QList<SeafDirent> dirents;
+ bool readonly;
+ if (data_mgr_->getDirents(repo_.id, "/", &dirents, &readonly)) {
+ onGetDirentsSuccess(readonly);
+ return;
+ }
+
+ data_mgr_->getDirentsFromServer(repo_.id, "/");
+}
+
+void CheckRepoRootDirPermDialog::onGetDirentsSuccess(bool readonly)
+{
+ has_write_perm_ = !readonly;
+ setValue(maximum());
+ accept();
+}
+
+void CheckRepoRootDirPermDialog::onGetDirentsFailed()
+{
+ has_write_perm_ = false;
+ setValue(maximum());
+ accept();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CHECK_REPO_ROOT_PERM_DIALOG_H
+#define SEAFILE_CLIENT_CHECK_REPO_ROOT_PERM_DIALOG_H
+
+#include <QUrl>
+#include <QString>
+#include <QProgressDialog>
+
+#include "api/server-repo.h"
+#include "account.h"
+#include "filebrowser/file-browser-dialog.h"
+
+class ApiError;
+class DataManager;
+class SeafDirent;
+
+// When the user drag'n'drop a file into to a repo and the repo is readonly, we
+// need to check the user's directory-level permission for the repo's root
+// directory.
+//
+// This dialog would be showed to the user when we send the request to the server.
+//
+class CheckRepoRootDirPermDialog : public QProgressDialog
+{
+ Q_OBJECT
+public:
+ CheckRepoRootDirPermDialog(const Account &account,
+ const ServerRepo& repo,
+ const QString& local_path,
+ QWidget *parent = 0);
+ ~CheckRepoRootDirPermDialog();
+
+ QString localPath() const { return local_path_; }
+ ServerRepo repo() const { return repo_; }
+
+ bool hasWritePerm() const { return has_write_perm_; }
+
+private slots:
+ void checkPerm();
+ void onGetDirentsSuccess(bool readonly);
+ void onGetDirentsFailed();
+
+private:
+ Q_DISABLE_COPY(CheckRepoRootDirPermDialog);
+
+ Account account_;
+ ServerRepo repo_;
+ QString local_path_;
+
+ bool has_write_perm_;
+
+ QLabel *description_label_;
+ QLabel *more_details_label_;
+ QProgressBar *progress_bar_;
+ DataManager *data_mgr_;
+ DataManagerNotify *data_mgr_notify_;
+};
+
+#endif // SEAFILE_CLIENT_CHECK_REPO_ROOT_PERM_DIALOG_H
--- /dev/null
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QTableView>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "clone-tasks-table-model.h"
+#include "clone-tasks-table-view.h"
+#include "clone-tasks-dialog.h"
+
+namespace {
+
+//const int kUpdateTasksInterval = 1000;
+
+enum {
+ INDEX_EMPTY_VIEW = 0,
+ INDEX_TASKS_VIEW
+};
+
+} // namespace
+
+
+CloneTasksDialog::CloneTasksDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ setWindowTitle(tr("Download tasks"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ setMinimumSize(QSize(600, 300));
+
+ createEmptyView();
+
+ table_ = new CloneTasksTableView;
+ model_ = new CloneTasksTableModel(this);
+ table_->setModel(model_);
+
+ stack_ = new QStackedWidget;
+ stack_->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+ stack_->insertWidget(INDEX_TASKS_VIEW, table_);
+
+ QVBoxLayout *vlayout = (QVBoxLayout *)layout();
+ vlayout->insertWidget(0, stack_);
+
+ mClearBtn->setToolTip(tr("remove all successful tasks"));
+ connect(mClearBtn, SIGNAL(clicked()), model_, SLOT(clearSuccessfulTasks()));
+
+ onModelReset();
+ connect(model_, SIGNAL(modelReset()), this, SLOT(onModelReset()));
+}
+
+void CloneTasksDialog::updateTasks()
+{
+ model_->updateTasks();
+}
+
+void CloneTasksDialog::onModelReset()
+{
+ if (model_->rowCount() == 0) {
+ stack_->setCurrentIndex(INDEX_EMPTY_VIEW);
+ } else {
+ stack_->setCurrentIndex(INDEX_TASKS_VIEW);
+ //table_->justifyColumnWidth();
+ }
+}
+
+
+void CloneTasksDialog::createEmptyView()
+{
+ empty_view_ = new QWidget(this);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ empty_view_->setLayout(layout);
+
+ QLabel *label = new QLabel;
+ label->setText(tr("No download tasks right now."));
+ label->setAlignment(Qt::AlignCenter);
+
+ layout->addWidget(label);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CLONE_TASKS_DIALOG_H
+#define SEAFILE_CLIENT_CLONE_TASKS_DIALOG_H
+
+#include <QDialog>
+#include "ui_clone-tasks-dialog.h"
+
+class QTimer;
+class QStackedWidget;
+
+class CloneTask;
+class CloneTasksTableView;
+class CloneTasksTableModel;
+
+class CloneTasksDialog : public QDialog,
+ public Ui::CloneTasksDialog
+{
+ Q_OBJECT
+
+public:
+ CloneTasksDialog(QWidget *parent=0);
+ void updateTasks();
+
+private slots:
+ void onModelReset();
+
+private:
+ void createEmptyView();
+ void addTaskItem(const CloneTask& task);
+
+ QStackedWidget *stack_;
+ CloneTasksTableView *table_;
+ CloneTasksTableModel *model_;
+ QWidget *empty_view_;
+};
+
+
+#endif // SEAFILE_CLIENT_CLONE_TASKS_DIALOG_H
--- /dev/null
+#include <QTimer>
+#include <QDir>
+
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "clone-tasks-table-model.h"
+
+namespace {
+
+const int kUpdateTasksInterval = 1000;
+
+enum {
+ COLUMN_NAME = 0,
+ COLUMN_WORK_TREE,
+ COLUMN_STATE,
+ MAX_COLUMN,
+};
+
+} // namespace
+
+CloneTasksTableModel::CloneTasksTableModel(QObject *parent)
+ : QAbstractTableModel(parent)
+{
+ update_timer_ = new QTimer(this);
+ connect(update_timer_, SIGNAL(timeout()), this, SLOT(updateTasks()));
+ update_timer_->start(kUpdateTasksInterval);
+
+ updateTasks();
+}
+
+void CloneTasksTableModel::updateTasks()
+{
+ std::vector<CloneTask> tasks;
+ int ret = seafApplet->rpcClient()->getCloneTasks(&tasks);
+ if (ret < 0) {
+ qDebug("failed to get clone tasks");
+ return;
+ }
+
+ beginResetModel();
+ if (tasks_.size() != tasks.size()) {
+ tasks_ = tasks;
+ endResetModel();
+ return;
+ }
+
+ for (int i = 0, n = tasks.size(); i < n; i++) {
+ if (tasks_[i] == tasks[i]) {
+ continue;
+ }
+
+ tasks_[i] = tasks[i];
+ QModelIndex start = QModelIndex().child(i, 0);
+ QModelIndex stop = QModelIndex().child(i, MAX_COLUMN - 1);
+ emit dataChanged(start, stop);
+ }
+ endResetModel();
+}
+
+int CloneTasksTableModel::rowCount(const QModelIndex& parent) const
+{
+ return tasks_.size();
+}
+
+int CloneTasksTableModel::columnCount(const QModelIndex& parent) const
+{
+ return MAX_COLUMN;
+}
+
+QVariant CloneTasksTableModel::data(const QModelIndex & index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ if (role != Qt::DisplayRole) {
+ return QVariant();
+ }
+
+ const CloneTask &task = tasks_[index.row()];
+
+ int column = index.column();
+
+ if (column == COLUMN_NAME) {
+ return task.repo_name;
+ } else if (column == COLUMN_WORK_TREE) {
+ return QDir::toNativeSeparators(task.worktree);
+ } else if (column == COLUMN_STATE) {
+ if (task.error_str.length() > 0) {
+ return task.error_str;
+ } else {
+ return task.state_str;
+ }
+ }
+
+ return QVariant();
+}
+
+QVariant CloneTasksTableModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Vertical) {
+ return QVariant();
+ }
+
+ if (section == COLUMN_NAME) {
+ if (role == Qt::DisplayRole) {
+ return tr("Library");
+ }
+ //else if (role == Qt::DecorationRole) {
+ // return awesome->icon(icon_cloud);
+ //}
+ } else if (section == COLUMN_WORK_TREE) {
+ if (role == Qt::DisplayRole) {
+ return tr("Path");
+ }
+ //else if (role == Qt::DecorationRole) {
+ // return awesome->icon(icon_folder_close_alt);
+ //}
+ }
+
+
+ return QVariant();
+}
+
+void CloneTasksTableModel::clearSuccessfulTasks()
+{
+ int n = tasks_.size();
+ for (int i = 0; i < n; i++) {
+ const CloneTask& task = tasks_[i];
+ if (task.isSuccessful()) {
+ QString error;
+ seafApplet->rpcClient()->removeCloneTask(task.repo_id, &error);
+ }
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CLONE_TASKS_TABLE_MODEL_H
+#define SEAFILE_CLIENT_CLONE_TASKS_TABLE_MODEL_H
+
+#include <QAbstractTableModel>
+#include <vector>
+
+#include "rpc/clone-task.h"
+
+class QTimer;
+
+class CloneTasksTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ CloneTasksTableModel(QObject *parent=0);
+
+ int rowCount(const QModelIndex& parent=QModelIndex()) const;
+ int columnCount(const QModelIndex& parent=QModelIndex()) const;
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ CloneTask taskAt(size_t i) const { return (i >= tasks_.size()) ? CloneTask() : tasks_[i]; }
+
+public slots:
+ void clearSuccessfulTasks();
+
+public slots:
+ void updateTasks();
+
+private:
+
+ std::vector<CloneTask> tasks_;
+ QTimer *update_timer_;
+};
+
+
+#endif // SEAFILE_CLIENT_CLONE_TASKS_TABLE_MODEL_H
--- /dev/null
+#include <QtGlobal>
+#include <QtWidgets>
+#include <QHeaderView>
+#include <QContextMenuEvent>
+
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "clone-tasks-table-model.h"
+#include "clone-tasks-table-view.h"
+
+
+CloneTasksTableHeader::CloneTasksTableHeader(QWidget *parent)
+ : QHeaderView(Qt::Horizontal, parent)
+{
+ sectionResizeMode(QHeaderView::Stretch);
+ setHighlightSections(false);
+}
+
+CloneTasksTableView::CloneTasksTableView(QWidget *parent)
+ : QTableView(parent)
+{
+ setHorizontalHeader(new CloneTasksTableHeader(this));
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ verticalHeader()->hide();
+
+ horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
+
+ createContextMenu();
+}
+
+void CloneTasksTableView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPoint pos = event->pos();
+ int row = rowAt(pos.y());
+ qDebug("row = %d\n", row);
+ if (row == -1) {
+ return;
+ }
+
+ CloneTasksTableModel *model = (CloneTasksTableModel *)this->model();
+
+ CloneTask task = model->taskAt(row);
+
+ prepareContextMenu(task);
+ pos = viewport()->mapToGlobal(pos);
+ context_menu_->exec(pos);
+}
+
+void CloneTasksTableView::prepareContextMenu(const CloneTask& task)
+{
+ if (task.isCancelable()) {
+ cancel_task_action_->setVisible(true);
+ cancel_task_action_->setData(task.repo_id);
+ } else {
+ cancel_task_action_->setVisible(false);
+ }
+
+ if (task.isRemovable()) {
+ remove_task_action_->setVisible(true);
+ remove_task_action_->setData(task.repo_id);
+ } else {
+ remove_task_action_->setVisible(false);
+ }
+}
+
+void CloneTasksTableView::createContextMenu()
+{
+ context_menu_ = new QMenu(this);
+
+ cancel_task_action_ = new QAction(tr("Cancel this task"), this);
+ cancel_task_action_->setIcon(awesome->icon(icon_remove));
+ cancel_task_action_->setStatusTip(tr("cancel this task"));
+ cancel_task_action_->setIconVisibleInMenu(true);
+ connect(cancel_task_action_, SIGNAL(triggered()), this, SLOT(cancelTask()));
+ context_menu_->addAction(cancel_task_action_);
+
+ remove_task_action_ = new QAction(tr("Remove this task"), this);
+ remove_task_action_->setIcon(awesome->icon(icon_remove));
+ remove_task_action_->setStatusTip(tr("Remove this task"));
+ remove_task_action_->setIconVisibleInMenu(true);
+ connect(remove_task_action_, SIGNAL(triggered()), this, SLOT(removeTask()));
+ context_menu_->addAction(remove_task_action_);
+}
+
+void CloneTasksTableView::cancelTask()
+{
+ QString repo_id = cancel_task_action_->data().toString();
+ QString error;
+ if (seafApplet->rpcClient()->cancelCloneTask(repo_id, &error) < 0) {
+ seafApplet->warningBox(
+ tr("Failed to cancel this task:\n\n %1").arg(error), this);
+ }
+}
+
+void CloneTasksTableView::removeTask()
+{
+ QString repo_id = remove_task_action_->data().toString();
+ QString error;
+ if (seafApplet->rpcClient()->removeCloneTask(repo_id, &error) < 0) {
+ seafApplet->warningBox(
+ tr("Failed to remove this task:\n\n %1").arg(error), this);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CLONE_TASKS_TABLE_VIEW_H
+#define SEAFILE_CLIENT_CLONE_TASKS_TABLE_VIEW_H
+
+#include <QTableView>
+#include <QHeaderView>
+
+class QAction;
+class QMenu;
+class QContextMenuEvent;
+
+class CloneTask;
+
+class CloneTasksTableView : public QTableView
+{
+ Q_OBJECT
+
+public:
+ CloneTasksTableView(QWidget *parent=0);
+
+ void contextMenuEvent(QContextMenuEvent *event);
+
+private slots:
+ void cancelTask();
+ void removeTask();
+
+private:
+ void createContextMenu();
+ void prepareContextMenu(const CloneTask& task);
+
+ QAction *cancel_task_action_;
+ QAction *remove_task_action_;
+ QMenu *context_menu_;
+};
+
+class CloneTasksTableHeader : public QHeaderView {
+ Q_OBJECT
+
+public:
+ CloneTasksTableHeader(QWidget *parent=0);
+};
+
+#endif // SEAFILE_CLIENT_CLONE_TASKS_TABLE_VIEW_H
--- /dev/null
+#include <QtGlobal>
+#include <vector>
+
+#include <QtWidgets>
+#include <QImage>
+#include <QWidget>
+
+#include "QtAwesome.h"
+#include "account-mgr.h"
+#include "account-view.h"
+#include "activities-tab.h"
+#include "clone-tasks-dialog.h"
+#include "create-repo-dialog.h"
+#include "customization-service.h"
+#include "main-window.h"
+#include "repos-tab.h"
+#include "rpc/rpc-client.h"
+#include "seafile-applet.h"
+#include "seafile-tab-widget.h"
+#include "search-tab.h"
+#include "server-status-dialog.h"
+#include "server-status-service.h"
+#include "starred-files-tab.h"
+#include "utils/paint-utils.h"
+#include "utils/utils-mac.h"
+#include "utils/utils-win.h"
+#include "utils/utils.h"
+
+#include "cloud-view.h"
+
+namespace
+{
+const int kRefreshStatusInterval = 1000;
+
+const int kIndexOfAccountView = 1;
+// const int kIndexOfToolBar = 2;
+const int kIndexOfTabWidget = 2;
+const char* kQuotaColorCritical = "#FF2A2A";
+const char* kQuotaColorWarning = "#FF9A2A";
+const char* kQuotaColorGood = "#92C87A";
+const char* kDrapInnerBorderColor = "#E4E4E4";
+const char* kDrapEnterBorderColor = "#ED6C00";
+
+enum {
+ TAB_INDEX_REPOS = 0,
+ TAB_INDEX_STARRED_FILES,
+ TAB_INDEX_ACTIVITIES,
+ TAB_INDEX_SEARCH,
+};
+
+QString translateTransferRate(int rate)
+{
+ QString unit;
+ QString display_rate;
+ double kbps = ((double)rate) / 1024;
+ if (kbps >= 1024) {
+ unit = "MB/s";
+ double mbps = kbps / 1024;
+ if (mbps < 10) {
+ display_rate = QString::number(mbps, 'f', 1);
+ } else {
+ display_rate = QString::number(int(mbps));
+ }
+ }
+ else {
+ display_rate = kbps;
+ unit = "kB/s";
+ display_rate = QString::number(int(kbps));
+ }
+
+ return QString("%1 %2")
+ .arg(display_rate)
+ .arg(unit);
+}
+}
+
+CloudView::CloudView(QWidget* parent)
+ : QWidget(parent), clone_task_dialog_(NULL)
+
+{
+ setupUi(this);
+
+ int marginTop = 0;
+ if (shouldUseFramelessWindow()) {
+ marginTop = 0;
+ }
+#ifdef Q_OS_MAC
+ marginTop = 0;
+#endif
+
+ layout()->setContentsMargins(1, marginTop, 1, 0);
+
+ // Setup widgets from top down
+ setupHeader();
+
+ createAccountView();
+
+ createTabs();
+
+ // tool bar have to be created after tabs, since some of the toolbar
+ // actions are provided by the tabs
+ // createToolBar();
+
+ setupDropArea();
+
+ setupFooter();
+
+ QVBoxLayout* vlayout = (QVBoxLayout*)layout();
+ vlayout->insertWidget(kIndexOfAccountView, account_view_);
+ vlayout->insertWidget(kIndexOfTabWidget, tabs_);
+
+ if (shouldUseFramelessWindow()) {
+ resizer_ = new QSizeGrip(this);
+ resizer_->resize(resizer_->sizeHint());
+ }
+
+ refresh_status_bar_timer_ = new QTimer(this);
+ connect(refresh_status_bar_timer_, SIGNAL(timeout()), this,
+ SLOT(refreshStatusBar()));
+
+ AccountManager* account_mgr = seafApplet->accountManager();
+ connect(account_mgr, SIGNAL(accountsChanged()), this,
+ SLOT(onAccountChanged()));
+ connect(account_mgr, SIGNAL(accountInfoUpdated(const Account&)), this,
+ SLOT(onAccountInfoUpdated(const Account&)));
+
+ if (!shouldUseFramelessWindow()) {
+ mHeader->setVisible(false);
+ }
+
+ connect(ServerStatusService::instance(), SIGNAL(serverStatusChanged()),
+ this, SLOT(refreshServerStatus()));
+ connect(CustomizationService::instance(),
+ SIGNAL(serverLogoFetched(const QUrl&)), this,
+ SLOT(onServerLogoFetched(const QUrl&)));
+
+ QTimer::singleShot(0, this, SLOT(onAccountChanged()));
+}
+
+void CloudView::setupHeader()
+{
+ setupLogoAndBrand();
+
+ mMinimizeBtn->setText("");
+ mMinimizeBtn->setToolTip(tr("Minimize"));
+ mMinimizeBtn->setIcon(awesome->icon(icon_minus, QColor("#808081")));
+ connect(mMinimizeBtn, SIGNAL(clicked()), this,
+ SLOT(onMinimizeBtnClicked()));
+
+ mCloseBtn->setText("");
+ mCloseBtn->setToolTip(tr("Close"));
+ mCloseBtn->setIcon(awesome->icon(icon_remove, QColor("#808081")));
+ connect(mCloseBtn, SIGNAL(clicked()), this, SLOT(onCloseBtnClicked()));
+
+ // Handle mouse move event
+ mHeader->installEventFilter(this);
+}
+
+
+void CloudView::createAccountView()
+{
+ account_view_ = new AccountView;
+// #ifdef Q_OS_MAC
+// account_view_->setContentsMargins(0, 0, 0, -8);
+// #else
+// account_view_->setContentsMargins(0, -8, 0, -8);
+// #endif
+ connect(account_view_, SIGNAL(refresh()),
+ this, SLOT(onRefreshClicked()));
+}
+
+void CloudView::createTabs()
+{
+ tabs_ = new SeafileTabWidget;
+ // tabs_ = new QTabWidget;
+
+ repos_tab_ = new ReposTab;
+
+ QString base_icon_path = ":/images/tabs/";
+ QString highlighted_base_icon_path = ":/images/tabs/highlighted/";
+ tabs_->addTab(repos_tab_, tr("Libraries"),
+ base_icon_path + "library-normal.png",
+ highlighted_base_icon_path + "library-orange.png");
+
+ starred_files_tab_ = new StarredFilesTab;
+ tabs_->addTab(starred_files_tab_, tr("Starred"),
+ base_icon_path + "star-normal.png",
+ highlighted_base_icon_path + "star-orange.png");
+
+ activities_tab_ = new ActivitiesTab;
+
+ search_tab_ = new SearchTab;
+
+ connect(tabs_, SIGNAL(currentTabChanged(int)), this,
+ SLOT(onTabChanged(int)));
+
+ showProperTabs();
+ // bool has_pro_account = hasAccount() &&
+ // seafApplet->accountManager()->accounts().front().isPro();
+ // if (has_pro_account) {
+ // addActivitiesTab();
+ // }
+}
+
+void CloudView::setupDropArea()
+{
+ mDropArea->setAcceptDrops(true);
+ mDropArea->installEventFilter(this);
+ connect(mSelectFolderBtn, SIGNAL(clicked()), this,
+ SLOT(chooseFolderToSync()));
+}
+
+void CloudView::setupFooter()
+{
+ // mDownloadTasksInfo->setText("0");
+ // mDownloadTasksBtn->setIcon(QIcon(":/images/toobar/download-gray.png"));
+ // mDownloadTasksBtn->setToolTip(tr("Show download tasks"));
+ // connect(mDownloadTasksBtn, SIGNAL(clicked()), this,
+ // SLOT(showCloneTasksDialog()));
+
+ mServerStatusBtn->setIconSize(QSize(10, 10));
+ connect(mServerStatusBtn, SIGNAL(clicked()), this,
+ SLOT(showServerStatusDialog()));
+
+ // mDownloadRateArrow->setText(QChar(icon_arrow_down));
+ // mDownloadRateArrow->setFont(awesome->font(16));
+ mDownloadRateArrow->setPixmap(QIcon(":/images/main-panel/download.png").pixmap(10));
+ mDownloadRateArrow->setAlignment(Qt::AlignVCenter);
+ mDownloadRate->setText("0 kB/s");
+ mDownloadRate->setToolTip(tr("current download rate"));
+ mDownloadRate->setAlignment(Qt::AlignVCenter | Qt::AlignRight);
+
+ // mUploadRateArrow->setText(QChar(icon_arrow_up));
+ // mUploadRateArrow->setFont(awesome->font(16));
+ mUploadRateArrow->setPixmap(QIcon(":/images/main-panel/upload.png").pixmap(10));
+ mUploadRateArrow->setAlignment(Qt::AlignVCenter);
+ mUploadRate->setText("0 kB/s");
+ mUploadRate->setToolTip(tr("current upload rate"));
+ mUploadRate->setAlignment(Qt::AlignVCenter | Qt::AlignRight);
+
+ mStorageUsage->reset();
+ mStorageUsage->setAlignment(Qt::AlignVCenter);
+}
+
+void CloudView::chooseFolderToSync()
+{
+ QString msg = tr("Please Choose a folder to sync");
+#if defined(Q_OS_WIN32)
+ QString parent_dir = "C:\\";
+#else
+ QString parent_dir = QDir::homePath();
+#endif
+ QString dir = QFileDialog::getExistingDirectory(
+ this, msg, parent_dir,
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+ if (dir.isEmpty()) {
+ return;
+ }
+
+ showCreateRepoDialog(dir);
+}
+
+void CloudView::showCreateRepoDialog(const QString& path)
+{
+ const std::vector<Account>& accounts =
+ seafApplet->accountManager()->accounts();
+ if (accounts.empty()) {
+ return;
+ }
+
+ CreateRepoDialog* dialog =
+ new CreateRepoDialog(accounts[0], path, repos_tab_, this);
+
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+void CloudView::onMinimizeBtnClicked()
+{
+ seafApplet->mainWindow()->showMinimized();
+}
+
+void CloudView::onCloseBtnClicked()
+{
+ seafApplet->mainWindow()->hide();
+}
+
+bool CloudView::eventFilter(QObject* obj, QEvent* event)
+{
+ if (obj == mHeader) {
+ static QPoint oldPos;
+ if (event->type() == QEvent::MouseButtonPress) {
+ QMouseEvent* ev = (QMouseEvent*)event;
+ oldPos = ev->globalPos();
+
+ return true;
+ }
+ else if (event->type() == QEvent::MouseMove) {
+ QMouseEvent* ev = (QMouseEvent*)event;
+ const QPoint delta = ev->globalPos() - oldPos;
+
+ MainWindow* win = seafApplet->mainWindow();
+ win->move(win->x() + delta.x(), win->y() + delta.y());
+
+ oldPos = ev->globalPos();
+ return true;
+ }
+ }
+ else if (obj == mDropArea) {
+ if (event->type() == QEvent::DragEnter) {
+ QDragEnterEvent* ev = (QDragEnterEvent*)event;
+ if (ev->mimeData()->hasUrls() &&
+ ev->mimeData()->urls().size() == 1) {
+ const QUrl url = ev->mimeData()->urls().at(0);
+ if (url.scheme() == "file") {
+ QString path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+ path = utils::mac::fix_file_id_url(path);
+#endif
+ if (QFileInfo(path).isDir()) {
+ QString style =
+ QString("QFrame#mDropInner {border: 1.5px dashed %1;}")
+ .arg(kDrapEnterBorderColor);
+ mDropInner->setStyleSheet(style);
+ ev->acceptProposedAction();
+ }
+ }
+ }
+ return true;
+ }
+ else if (event->type() == QEvent::Drop) {
+ QDropEvent* ev = (QDropEvent*)event;
+ const QUrl url = ev->mimeData()->urls().at(0);
+ QString path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+ path = utils::mac::fix_file_id_url(path);
+#endif
+ ev->setDropAction(Qt::CopyAction);
+ ev->accept();
+ QString style =
+ QString("QFrame#mDropInner {border: 1.5px dashed %1;}")
+ .arg(kDrapInnerBorderColor);
+ mDropInner->setStyleSheet(style);
+ showCreateRepoDialog(path);
+ return true;
+ }
+ else if (event->type() == QEvent::DragLeave) {
+ QDragLeaveEvent* ev = static_cast<QDragLeaveEvent*>(event);
+ dragLeaveEvent(ev);
+ QString style =
+ QString("QFrame#mDropInner {border: 1.5px dashed %1;}")
+ .arg(kDrapInnerBorderColor);
+ mDropInner->setStyleSheet(style);
+ return true;
+ }
+ }
+
+ return QWidget::eventFilter(obj, event);
+}
+
+CloneTasksDialog* CloudView::cloneTasksDialog()
+{
+ if (clone_task_dialog_ == NULL) {
+ clone_task_dialog_ = new CloneTasksDialog;
+ }
+
+ return clone_task_dialog_;
+}
+
+bool CloudView::hasAccount()
+{
+ return seafApplet->accountManager()->hasAccount();
+}
+
+void CloudView::showEvent(QShowEvent* event)
+{
+ QWidget::showEvent(event);
+
+ refresh_status_bar_timer_->start(kRefreshStatusInterval);
+}
+
+void CloudView::hideEvent(QHideEvent* event)
+{
+ QWidget::hideEvent(event);
+ refresh_status_bar_timer_->stop();
+}
+
+
+void CloudView::refreshTasksInfo()
+{
+ int count = 0;
+ if (seafApplet->rpcClient()->getCloneTasksCount(&count) < 0) {
+ return;
+ }
+
+ // mDownloadTasksInfo->setText(QString::number(count));
+}
+
+void CloudView::refreshServerStatus()
+{
+ ServerStatusService* service = ServerStatusService::instance();
+ QString tool_tip;
+ if (service->allServersConnected()) {
+ tool_tip = tr("all servers connected");
+ }
+ else if (service->allServersDisconnected()) {
+ tool_tip = tr("no server connected");
+ }
+ else {
+ tool_tip = tr("some servers not connected");
+ }
+
+ if (!service->allServersConnected()) {
+ mServerStatusBtn->setIcon(
+ QIcon(":/images/main-panel/network-error.png"));
+ mServerStatusBtn->show();
+ } else {
+ mServerStatusBtn->hide();
+ }
+
+ mServerStatusBtn->setToolTip(tool_tip);
+}
+
+void CloudView::refreshTransferRate()
+{
+ int up_rate, down_rate;
+ if (seafApplet->rpcClient()->getUploadRate(&up_rate) < 0) {
+ return;
+ }
+
+ if (seafApplet->rpcClient()->getDownloadRate(&down_rate) < 0) {
+ return;
+ }
+
+ mUploadRate->setText(translateTransferRate(up_rate));
+ mDownloadRate->setText(translateTransferRate(down_rate));
+}
+
+void CloudView::refreshStatusBar()
+{
+ if (!seafApplet->mainWindow()->isVisible()) {
+ return;
+ }
+ refreshTasksInfo();
+ refreshTransferRate();
+}
+
+void CloudView::showCloneTasksDialog()
+{
+ // CloneTasksDialog dialog(this);
+ if (clone_task_dialog_ == NULL) {
+ clone_task_dialog_ = new CloneTasksDialog;
+ }
+
+ clone_task_dialog_->updateTasks();
+ clone_task_dialog_->show();
+ clone_task_dialog_->raise();
+ clone_task_dialog_->activateWindow();
+}
+
+void CloudView::showServerStatusDialog()
+{
+ ServerStatusDialog dialog(this);
+ dialog.exec();
+}
+
+void CloudView::onRefreshClicked()
+{
+ if (tabs_->currentIndex() == TAB_INDEX_REPOS) {
+ repos_tab_->refresh();
+ }
+ else if (tabs_->currentIndex() == TAB_INDEX_STARRED_FILES) {
+ starred_files_tab_->refresh();
+ }
+ else if (tabs_->currentIndex() == TAB_INDEX_ACTIVITIES) {
+ activities_tab_->refresh();
+ }
+ else if (tabs_->currentIndex() == TAB_INDEX_SEARCH) {
+ search_tab_->refresh();
+ }
+}
+
+void CloudView::resizeEvent(QResizeEvent* event)
+{
+ if (shouldUseFramelessWindow()) {
+ resizer_->move(rect().bottomRight() - resizer_->rect().bottomRight());
+ resizer_->raise();
+ }
+
+ tabs_->adjustTabsWidth(rect().width());
+}
+
+void CloudView::onServerLogoFetched(const QUrl& url)
+{
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ if (account.isValid() && url.host() == account.serverUrl.host()) {
+ mLogo->setPixmap(
+ CustomizationService::instance()->getServerLogo(account));
+ }
+}
+
+void CloudView::setupLogoAndBrand()
+{
+ mLogo->setText("");
+ mLogo->setToolTip(getBrand());
+ QPixmap logo;
+ // We must get the pixmap from a QImage, otherwise the logo won't be
+ // updated when we switch between two accounts, one of which has custom
+ // logo and the other doesn't.
+ logo.convertFromImage(QImage(":/images/seafile-24.png"));
+ mLogo->setPixmap(logo);
+
+ mBrand->setText(getBrand());
+ mBrand->setToolTip(getBrand());
+}
+
+void CloudView::onAccountChanged()
+{
+ setupLogoAndBrand();
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ if (account.isValid() && account.isPro()) {
+ if (!account.serverInfo.customBrand.isEmpty()) {
+ QString title = account.serverInfo.customBrand;
+ mBrand->setText(title);
+ mBrand->setToolTip(title);
+ mLogo->setToolTip(title);
+ if (seafApplet->mainWindow()) {
+ seafApplet->mainWindow()->setWindowTitle(title);
+ }
+ }
+
+ if (!account.serverInfo.customLogo.isEmpty()) {
+ mLogo->setPixmap(
+ CustomizationService::instance()->getServerLogo(account));
+ }
+ }
+
+ // refresh_action_->setEnabled(account.isValid());
+
+ showProperTabs();
+
+ repos_tab_->refresh();
+ starred_files_tab_->refresh();
+ if (seafApplet->accountManager()->currentAccount().isPro()) {
+ activities_tab_->refresh();
+ }
+ search_tab_->reset();
+
+ account_view_->onAccountChanged();
+ // we need update tab manually
+ onTabChanged(tabs_->currentIndex());
+
+ updateStorageUsage(account);
+}
+
+void CloudView::updateStorageUsage(const Account& account)
+{
+ if (!account.isValid()) {
+ mStorageUsage->hide();
+ return;
+ }
+ mStorageUsage->show();
+ const AccountInfo& info = account.accountInfo;
+ if (info.totalStorage > 0) {
+ mStorageUsage->setMaximum(info.totalStorage / 1000);
+ mStorageUsage->setValue(qMax(info.usedStorage / 1000, 3 * info.totalStorage / (100 * 1000)));
+ mStorageUsage->setVisible(true);
+ QString msg = ::readableFileSize(info.usedStorage) + "/" +
+ ::readableFileSize(info.totalStorage);
+ mStorageUsage->setFormat(msg);
+ mStorageUsage->setToolTip(msg);
+ int percent = info.usedStorage * 100.0 / info.totalStorage;
+ QString color;
+ if (percent >= 80) {
+ color = kQuotaColorCritical;
+ }
+ else if (percent >= 50) {
+ color = kQuotaColorWarning;
+ }
+ else {
+ color = kQuotaColorGood;
+ }
+ QString style =
+ QString("QProgressBar::chunk {background-color: %1; width: 3px;}")
+ .arg(color);
+ mStorageUsage->setStyleSheet(style);
+ }
+ else {
+ mStorageUsage->setVisible(false);
+ mStorageUsage->setToolTip("");
+ }
+ mStorageUsage->setTextVisible(false);
+}
+
+void CloudView::showProperTabs()
+{
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ bool show_activities_tab = false;
+ bool show_search_tab = false;
+ if (tabs_->count() > 2) {
+ tabs_->removeTab(TAB_INDEX_SEARCH, search_tab_);
+ tabs_->removeTab(TAB_INDEX_ACTIVITIES, activities_tab_);
+ }
+ if (account.isPro()) {
+ show_activities_tab = true;
+ if (account.hasFileSearch()) {
+ show_search_tab = true;
+ }
+ if (show_activities_tab) {
+ tabs_->addTab(activities_tab_, tr("Activities"),
+ ":/images/tabs/history-normal.png",
+ ":/images/tabs/highlighted/history-orange.png");
+ }
+ if (show_search_tab) {
+ tabs_->addTab(search_tab_, tr("Search"),
+ ":/images/tabs/search-normal.png",
+ ":/images/tabs/highlighted/search-orange.png");
+ }
+ }
+ tabs_->adjustTabsWidth(rect().width());
+}
+
+void CloudView::onTabChanged(int index)
+{
+ bool enable_sync_with_any_folder = hasAccount() &&
+ !seafApplet->accountManager()
+ ->accounts()
+ .front()
+ .hasDisableSyncWithAnyFolder();
+ bool drop_area_visible = index == 0;
+ if (enable_sync_with_any_folder && drop_area_visible) {
+ mDropArea->setVisible(true);
+ mFooter->setStyleSheet("");
+ }
+ else {
+ mDropArea->setVisible(false);
+ mFooter->setStyleSheet(
+ "QFrame#mFooter { border-top: 1px solid #DCDCDE; }");
+ }
+}
+
+void CloudView::onAccountInfoUpdated(const Account& account)
+{
+ if (account == seafApplet->accountManager()->currentAccount()) {
+ updateStorageUsage(account);
+ account_view_->onAccountChanged();
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_CLOUD_VIEW_H
+#define SEAFILE_CLIENT_CLOUD_VIEW_H
+
+#include <QWidget>
+#include "ui_cloud-view.h"
+
+class QTimer;
+class QShowEvent;
+class QHideEvent;
+class QToolButton;
+class QToolBar;
+class QSizeGrip;
+class QTabWidget;
+class QUrl;
+
+class SeafileTabWidget;
+class ReposTab;
+class StarredFilesTab;
+class ActivitiesTab;
+class SearchTab;
+class CloneTasksDialog;
+class AccountView;
+class Account;
+
+class CloudView : public QWidget,
+ public Ui::CloudView
+{
+ Q_OBJECT
+public:
+ CloudView(QWidget *parent=0);
+
+ CloneTasksDialog* cloneTasksDialog();
+
+protected:
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
+ void resizeEvent(QResizeEvent *event);
+ bool eventFilter(QObject *obj, QEvent *ev);
+
+public slots:
+ void showCloneTasksDialog();
+
+private slots:
+ void refreshStatusBar();
+ void showServerStatusDialog();
+ void onRefreshClicked();
+ void onMinimizeBtnClicked();
+ void onCloseBtnClicked();
+ void chooseFolderToSync();
+ void onAccountChanged();
+ void onTabChanged(int index);
+ void refreshServerStatus();
+ void onServerLogoFetched(const QUrl& url);
+ void onAccountInfoUpdated(const Account& account);
+
+private:
+ Q_DISABLE_COPY(CloudView)
+
+ bool hasAccount();
+
+ void setupHeader();
+ void setupLogoAndBrand();
+ void createAccountView();
+ void createTabs();
+ void setupDropArea();
+ void setupFooter();
+ void showProperTabs();
+
+ void refreshTasksInfo();
+ void refreshTransferRate();
+ void showCreateRepoDialog(const QString& path);
+ void updateStorageUsage(const Account& account);
+
+ QTimer *refresh_status_bar_timer_;
+
+ AccountView *account_view_;
+
+ SeafileTabWidget *tabs_;
+ ReposTab *repos_tab_;
+ StarredFilesTab *starred_files_tab_;
+ ActivitiesTab *activities_tab_;
+ SearchTab *search_tab_;
+
+ QSizeGrip *resizer_;
+
+ CloneTasksDialog* clone_task_dialog_;
+};
+
+
+#endif // SEAFILE_CLIENT_CLOUD_VIEW_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include <QUuid>
+
+#include "utils/utils.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "repo-service.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "rpc/rpc-client.h"
+#include "ui/create-repo-dialog.h"
+#include "ui/repos-tab.h"
+
+CreateRepoDialog::CreateRepoDialog(const Account& account,
+ const QString& worktree,
+ ReposTab *repos_tab,
+ QWidget *parent)
+ : QDialog(parent),
+ path_(worktree),
+ request_(NULL),
+ account_(account),
+ repos_tab_(repos_tab)
+{
+ setupUi(this);
+ setWindowTitle(tr("Create a library"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+#if defined(Q_OS_MAC)
+ layout()->setContentsMargins(6, 6, 6, 6);
+ layout()->setSpacing(5);
+#endif
+
+ mStatusText->setText("");
+
+ mDirectory->setText(worktree);
+ mName->setText(QDir(worktree).dirName());
+
+ connect(mChooseDirBtn, SIGNAL(clicked()), this, SLOT(chooseDirAction()));
+ connect(mOkBtn, SIGNAL(clicked()), this, SLOT(createAction()));
+
+ const QRect screen = QApplication::desktop()->screenGeometry();
+ move(screen.center() - this->rect().center());
+}
+
+CreateRepoDialog::~CreateRepoDialog()
+{
+ if (request_) {
+ request_->deleteLater();
+ request_ = nullptr;
+ }
+}
+
+void CreateRepoDialog::chooseDirAction()
+{
+ QString dir = QFileDialog::getExistingDirectory(this, tr("Please choose a directory"),
+ mDirectory->text(),
+ QFileDialog::ShowDirsOnly
+ | QFileDialog::DontResolveSymlinks);
+ if (dir.isEmpty())
+ return;
+ mDirectory->setText(dir);
+ QDir d(dir);
+ mName->setText(d.dirName());
+}
+
+void CreateRepoDialog::setAllInputsEnabled(bool enabled)
+{
+ mOkBtn->setEnabled(enabled);
+ mChooseDirBtn->setEnabled(enabled);
+ mDirectory->setEnabled(enabled);
+ mName->setEnabled(enabled);
+ mEncrypteCheckBox->setEnabled(enabled);
+
+ bool password_enabled = (mEncrypteCheckBox->checkState() == Qt::Checked) && enabled;
+ mPassword->setEnabled(password_enabled);
+ mPasswordAgain->setEnabled(password_enabled);
+}
+
+void CreateRepoDialog::createAction()
+{
+ if (!validateInputs()) {
+ return;
+ }
+ mStatusText->setText(tr("Creating..."));
+
+ setAllInputsEnabled(false);
+
+ if (request_) {
+ request_->deleteLater();
+ request_ = nullptr;
+ }
+
+ if (!passwd_.isEmpty() && account_.isAtLeastVersion(4, 4, 0)) {
+ // TODO: check server version is at least 4.3.x ?
+ QString repo_id = QUuid::createUuid().toString().mid(1, 36);
+ QString magic, random_key, salt;
+
+ int enc_version = seafApplet->accountManager()->currentAccount().getEncryptedLibraryVersion();
+
+ if (seafApplet->rpcClient()->generateMagicAndRandomKey(
+ enc_version, repo_id, passwd_, &magic, &random_key, &salt) < 0) {
+ seafApplet->warningBox(tr("Failed to generate encryption key for this library"), this);
+ return;
+ }
+ // printf ("magic is %s, random_key is %s salt is %s\n", toCStr(magic), toCStr(random_key), toCStr(salt));
+
+ if (enc_version == 3) {
+ request_ = new CreateRepoRequest(
+ account_, name_, name_, enc_version, repo_id, magic, random_key, salt);
+ } else {
+ request_ = new CreateRepoRequest(
+ account_, name_, name_, enc_version, repo_id, magic, random_key);
+ }
+ } else {
+ request_ = new CreateRepoRequest(account_, name_, name_, passwd_);
+ }
+
+ connect(request_, SIGNAL(success(const RepoDownloadInfo&)),
+ this, SLOT(createSuccess(const RepoDownloadInfo&)));
+
+ connect(request_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(createFailed(const ApiError&)));
+
+ request_->send();
+}
+
+bool CreateRepoDialog::validateInputs()
+{
+ QString path;
+ QString passwd;
+ QString passwdAgain;
+ bool encrypted;
+
+ path = mDirectory->text();
+ if (path.isEmpty()) {
+ seafApplet->warningBox(tr("Please choose the directory to sync"), this);
+ return false;
+ }
+ if (!QDir(path).exists()) {
+ seafApplet->warningBox(tr("The folder %1 does not exist").arg(path), this);
+ return false;
+ }
+
+ if (mName->text().trimmed().isEmpty()) {
+ seafApplet->warningBox(tr("Please enter the name"), this);
+ return false;
+ }
+
+ encrypted = mEncrypteCheckBox->checkState() == Qt::Checked;
+ if (encrypted) {
+ if (mPassword->text().trimmed().isEmpty() ||
+ mPasswordAgain->text().trimmed().isEmpty()) {
+ seafApplet->warningBox(tr("Please enter the password"), this);
+ return false;
+ }
+
+ passwd = mPassword->text().trimmed();
+ passwdAgain = mPasswordAgain->text().trimmed();
+ if (passwd != passwdAgain) {
+ seafApplet->warningBox(tr("Passwords don't match"), this);
+ return false;
+ }
+ passwd_ = passwd;
+ } else {
+ passwd_ = QString::null;
+ }
+
+ QString error;
+ if (seafApplet->rpcClient()->checkPathForClone(path, &error) < 0) {
+ if (error.isEmpty()) {
+ error = tr("Unknown error");
+ }
+ seafApplet->warningBox(translateErrorMsg(error), this);
+ return false;
+ }
+
+ name_ = mName->text().trimmed();
+ path_ = mDirectory->text();
+ return true;
+}
+
+void CreateRepoDialog::createSuccess(const RepoDownloadInfo& info)
+{
+ QString error;
+
+ int ret = seafApplet->rpcClient()->cloneRepo(
+ info.repo_id,
+ info.repo_version,
+ info.repo_name,
+ path_,
+ info.token,
+ passwd_,
+ info.magic,
+ info.email,
+ info.random_key,
+ info.enc_version,
+ info.more_info,
+ &error);
+
+ if (ret < 0) {
+ error = translateErrorMsg(error);
+ seafApplet->warningBox(tr("Failed to add download task:\n %1").arg(error), this);
+ setAllInputsEnabled(true);
+ } else {
+ repos_tab_->refresh();
+ done(QDialog::Accepted);
+ }
+}
+
+void CreateRepoDialog::createFailed(const ApiError& error)
+{
+ mStatusText->setText("");
+
+ QString msg = tr("Failed to create library on the server:\n%1").arg(error.toString());
+
+ seafApplet->warningBox(msg, this);
+
+ setAllInputsEnabled(true);
+}
+
+QString CreateRepoDialog::translateErrorMsg(const QString& error)
+{
+ if (error == "Worktree conflicts system path") {
+ return QObject::tr("The path \"%1\" conflicts with system path").arg(path_);
+ } else if (error == "Worktree conflicts existing repo") {
+ return QObject::tr("The path \"%1\" conflicts with an existing library").arg(path_);
+ }
+ return error;
+}
--- /dev/null
+#include <QDialog>
+#include <QUrl>
+#include <QString>
+
+#include "ui_create-repo-dialog.h"
+#include "account.h"
+
+class CreateRepoRequest;
+class RepoDownloadInfo;
+class ApiError;
+class ReposTab;
+
+class CreateRepoDialog : public QDialog,
+ public Ui::CreateRepoDialog
+{
+ Q_OBJECT
+public:
+ CreateRepoDialog(const Account& account,
+ const QString& worktree,
+ ReposTab *repos_tab,
+ QWidget *parent=0);
+
+ ~CreateRepoDialog();
+
+private slots:
+ void createAction();
+ void chooseDirAction();
+ void createSuccess(const RepoDownloadInfo& info);
+ void createFailed(const ApiError& error);
+
+private:
+ Q_DISABLE_COPY(CreateRepoDialog);
+ bool validateInputs();
+ void setAllInputsEnabled(bool enabled);
+ QString translateErrorMsg(const QString& error);
+
+ QString path_;
+ QString name_;
+ QString passwd_;
+ CreateRepoRequest *request_;
+ Account account_;
+ ReposTab *repos_tab_;
+};
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QDirIterator>
+#include <QTimer>
+
+#include <jansson.h>
+
+#include "account-mgr.h"
+#include "settings-mgr.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "configurator.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "api/server-repo.h"
+#include "repo-service.h"
+#include "download-repo-dialog.h"
+
+namespace {
+const int kAlternativeTryTimes = 20;
+bool inline isPathInWorktree(const QString& worktree, const QString &path)
+{
+ if (path == worktree) {
+ return true;
+ }
+ QDir dir(worktree);
+ if (dir.relativeFilePath(QFileInfo(path).absoluteFilePath()).startsWith("."))
+ return false;
+ return true;
+}
+
+bool isPathConflictWithExistingRepo(const QString &path, QString *repo_name) {
+ RepoService::instance()->refreshLocalRepoList();
+ const std::vector<LocalRepo> & repos = RepoService::instance()->localRepos();
+ for (unsigned i = 0; i < repos.size(); ++i) {
+ // compare case insensitive file names as well
+ if (QFileInfo(repos[i].worktree) == QFileInfo(path)) {
+ *repo_name = repos[i].name;
+ return true;
+ }
+ }
+ return false;
+}
+
+QString getAlternativePath(const QString &dir_path, const QString &name) {
+ QDir dir = QDir(dir_path);
+ QFileInfo file;
+ file = QFileInfo(dir.filePath(name));
+ int i;
+ for (i = 1; i < kAlternativeTryTimes; ++i) {
+ if (!file.exists() && dir.mkdir(file.fileName()))
+ return file.absoluteFilePath();
+ file = QFileInfo(dir.filePath(name + "-" + QString::number(i)));
+ }
+
+ return QString();
+}
+
+inline QString getOperatingText(const ServerRepo &repo) {
+ if (!repo.isSubfolder()) {
+ return QObject::tr("Sync this library to:");
+ } else {
+ return QObject::tr("Sync this folder to:");
+ }
+}
+} // anonymous namespace
+
+DownloadRepoDialog::DownloadRepoDialog(const Account& account,
+ const ServerRepo& repo,
+ const QString& password,
+ QWidget *parent)
+ : QDialog(parent),
+ repo_(repo),
+ account_(account),
+ merge_without_question_(false),
+ resync_mode_(false)
+{
+ manual_merge_mode_ = false;
+ setupUi(this);
+ if (!repo.isSubfolder()) {
+ setWindowTitle(tr("Sync library \"%1\"").arg(repo_.name));
+ }
+ else {
+ setWindowTitle(tr("Sync folder \"%1\"").arg(repo.parent_path));
+ }
+ mDirectory->setPlaceholderText(getOperatingText(repo_));
+ mDirectory->setReadOnly(true);
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ mRepoIcon->setPixmap(repo.getPixmap());
+ mRepoName->setText(repo_.name);
+ mOperationText->setText(tr("Sync to folder:"));
+
+ if (repo_.encrypted) {
+ if (!password.isEmpty()) {
+ mPassword->setText(password);
+ mPassword->setReadOnly(true);
+ }
+ mPassword->setVisible(true);
+ mPasswordLabel->setVisible(true);
+ } else {
+ mPassword->setVisible(false);
+ mPasswordLabel->setVisible(false);
+ }
+
+ int height = 250;
+#if defined(Q_OS_MAC)
+ layout()->setContentsMargins(8, 9, 9, 5);
+ layout()->setSpacing(6);
+ verticalLayout_3->setSpacing(6);
+#endif
+ if (repo.encrypted) {
+ height += 50;
+ }
+ setMinimumHeight(height);
+ setMaximumHeight(height);
+
+ setDirectoryText(seafApplet->configurator()->worktreeDir());
+
+ connect(mSwitchModeHint, SIGNAL(linkActivated(const QString &)),
+ this, SLOT(switchMode()));
+
+ updateSyncMode();
+
+ mMergeHint->hide();
+
+ connect(mChooseDirBtn, SIGNAL(clicked()), this, SLOT(chooseDirAction()));
+ connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+
+ QTimer::singleShot(1000, this, SLOT(startResync()));
+}
+
+void DownloadRepoDialog::startResync()
+{
+ if (!resync_mode_) {
+ return;
+ }
+ onOkBtnClicked();
+}
+
+void DownloadRepoDialog::switchMode()
+{
+ manual_merge_mode_ = !manual_merge_mode_;
+
+ QString path = mDirectory->text().trimmed();
+ if (!path.isEmpty()) {
+ // from download new to merge existing
+ if (manual_merge_mode_) {
+ setDirectoryText(::pathJoin(path, repo_.name));
+ } else {
+ // from merge existing to download new
+ if (::getBaseName(path) == repo_.name) {
+ setDirectoryText(::getParentPath(path));
+ }
+ }
+ }
+
+ updateSyncMode();
+}
+
+void DownloadRepoDialog::updateSyncMode()
+{
+ if (account_.hasDisableSyncWithAnyFolder()) {
+ sync_with_existing_ = false;
+ manual_merge_mode_ = false;
+ mOperationText->setVisible(false);
+ mSwitchModeHint->setVisible(false);
+ return;
+ }
+ QString switch_hint_text;
+ QString op_text;
+ const QString link_template = "<a style=\"color:#FF9A2A\" href=\"#\">%1</a>";
+
+ QString OR = tr("or");
+ if (!manual_merge_mode_) {
+ op_text = getOperatingText(repo_);
+ sync_with_existing_ = false;
+
+ QString link = link_template.arg(tr("sync with an existing folder"));
+ switch_hint_text = QString("%1 %2").arg(OR).arg(link);
+
+ } else {
+ QString link = link_template.arg(tr("create a new sync folder"));
+ switch_hint_text = QString("%1 %2").arg(OR).arg(link);
+ sync_with_existing_ = true;
+
+ op_text = tr("Sync with this existing folder:");
+
+ if (!alternative_path_.isNull()) {
+ setDirectoryText(alternative_path_);
+ }
+ }
+
+ mOperationText->setText(op_text);
+ mSwitchModeHint->setText(switch_hint_text);
+}
+
+void DownloadRepoDialog::setDirectoryText(const QString& path)
+{
+ QString text = path;
+ if (text.endsWith("/")) {
+ text.resize(text.size() - 1);
+ }
+
+ mDirectory->setText(text);
+
+ if (manual_merge_mode_) {
+ alternative_path_ = text;
+ }
+}
+
+void DownloadRepoDialog::chooseDirAction()
+{
+ const QString &wt = seafApplet->configurator()->worktreeDir();
+ QString dir = QFileDialog::getExistingDirectory(this, tr("Please choose a folder"),
+ wt.toUtf8().data(),
+ QFileDialog::ShowDirsOnly
+ | QFileDialog::DontResolveSymlinks);
+ if (dir.isEmpty())
+ return;
+ setDirectoryText(dir);
+}
+
+void DownloadRepoDialog::onOkBtnClicked()
+{
+ if (!validateInputs()) {
+ return;
+ }
+
+ setAllInputsEnabled(false);
+
+ DownloadRepoRequest *req = new DownloadRepoRequest(account_, repo_.id, repo_.readonly);
+ connect(req, SIGNAL(success(const RepoDownloadInfo&)),
+ this, SLOT(onDownloadRepoRequestSuccess(const RepoDownloadInfo&)));
+ connect(req, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onDownloadRepoRequestFailed(const ApiError&)));
+ req->send();
+}
+
+bool DownloadRepoDialog::validateInputDirectory()
+{
+ QDir dir(mDirectory->text());
+ if (!dir.exists()) {
+ seafApplet->warningBox(tr("The folder does not exist"));
+ return false;
+ }
+ return true;
+}
+
+bool DownloadRepoDialog::validateInputs()
+{
+ setDirectoryText(mDirectory->text().trimmed());
+ if (mDirectory->text().isEmpty()) {
+ seafApplet->warningBox(tr("Please choose the folder to sync."));
+ return false;
+ }
+ if (account_.hasDisableSyncWithAnyFolder() &&
+ !isPathInWorktree(seafApplet->configurator()->worktreeDir(), mDirectory->text())) {
+ seafApplet->warningBox(
+ tr("Your organization disables putting a library outside %1 folder.").arg(getBrand()));
+ return false;
+ }
+ if (repo_.encrypted) {
+ mPassword->setText(mPassword->text().trimmed());
+ if (mPassword->text().isEmpty()) {
+ seafApplet->warningBox(tr("Please enter the password"));
+ return false;
+ }
+ }
+
+ if (!validateInputDirectory()) {
+ return false;
+ }
+
+ if (manual_merge_mode_) {
+ return true;
+ }
+
+ sync_with_existing_ = false;
+ alternative_path_ = "";
+
+ QString path = QDir(mDirectory->text()).absoluteFilePath(repo_.name);
+ QFileInfo fileinfo = QFileInfo(path);
+ if (fileinfo.exists()) {
+ sync_with_existing_ = true;
+ // exist and but not a directory ?
+ if (!fileinfo.isDir()) {
+ seafApplet->warningBox(
+ tr("Conflicting with existing file \"%1\", please choose a different folder.").arg(path));
+ return false;
+ }
+ // exist and but conflicting?
+ QString repo_name;
+ if (isPathConflictWithExistingRepo(path, &repo_name)) {
+ seafApplet->warningBox(
+ tr("Conflicting with existing library \"%1\", please choose a different folder.").arg(repo_name));
+ return false;
+ }
+ QMessageBox::StandardButton ret = merge_without_question_
+ ? QMessageBox::Yes
+ : seafApplet->yesNoCancelBox(
+ tr("The folder \"%1\" already exists. Are you sure to sync with it (contents will be merged)?")
+ .arg(path) + QString("<br/><br/><small>%1</small>").arg(tr("Click No to sync with a new folder instead")),
+ this, QMessageBox::Yes);
+ if (ret == QMessageBox::Cancel)
+ return false;
+ if (ret == QMessageBox::No) {
+ QString new_path = getAlternativePath(mDirectory->text(), repo_.name);
+ if (new_path.isEmpty()) {
+ seafApplet->warningBox(tr("Unable to find an alternative folder name").arg(path));
+ return false;
+ }
+ alternative_path_ = new_path;
+ }
+ }
+
+ return true;
+}
+
+void DownloadRepoDialog::setAllInputsEnabled(bool enabled)
+{
+ mDirectory->setEnabled(enabled);
+ mChooseDirBtn->setEnabled(enabled);
+ mPassword->setEnabled(enabled);
+ mOkBtn->setEnabled(enabled);
+}
+
+void DownloadRepoDialog::onDownloadRepoRequestSuccess(const RepoDownloadInfo& info)
+{
+ QString worktree = mDirectory->text();
+ QString password = repo_.encrypted ? mPassword->text() : QString();
+ int ret = 0;
+ QString error;
+
+ if (sync_with_existing_) {
+ if (alternative_path_.isEmpty())
+ worktree = QDir(worktree).absoluteFilePath(repo_.name);
+ else
+ worktree = alternative_path_;
+ ret = seafApplet->rpcClient()->cloneRepo(info.repo_id, info.repo_version,
+ repo_.name, worktree,
+ info.token, password,
+ info.magic, info.email,
+ info.random_key, info.enc_version,
+ info.more_info,
+ &error);
+ } else {
+ ret = seafApplet->rpcClient()->downloadRepo(info.repo_id, info.repo_version,
+ repo_.name, worktree,
+ info.token, password,
+ info.magic, info.email,
+ info.random_key, info.enc_version,
+ info.more_info,
+ &error);
+ }
+
+ if (ret < 0) {
+ if (error == "Worktree conflicts system path") {
+ error = QObject::tr("The path \"%1\" conflicts with system path").arg(worktree);
+ } else if (error == "Worktree conflicts existing repo") {
+ error = QObject::tr("The path \"%1\" conflicts with an existing library").arg(worktree);
+ } else if (error == "Library name contains invalid characters such as ':', '*', '|', '?'") {
+ error = QObject::tr("Library name contains invalid characters such as ':', '*', '|', '?'");
+ }
+ seafApplet->warningBox(tr("Failed to add download task:\n %1").arg(error), this);
+ setAllInputsEnabled(true);
+ } else {
+ done(QDialog::Accepted);
+ }
+}
+
+
+void DownloadRepoDialog::onDownloadRepoRequestFailed(const ApiError& error)
+{
+ QString msg = tr("Failed to get repo download information:\n%1").arg(error.toString());
+
+ seafApplet->warningBox(msg, this);
+
+ setAllInputsEnabled(true);
+}
+
+void DownloadRepoDialog::setMergeWithExisting(const QString& localPath) {
+ merge_without_question_ = true;
+ setDirectoryText(localPath);
+}
+
+void DownloadRepoDialog::setResyncMode() {
+ resync_mode_ = true;
+ setAllInputsEnabled(false);
+}
--- /dev/null
+#include <QDialog>
+#include <QUrl>
+#include <QString>
+
+#include "account.h"
+#include "ui_download-repo-dialog.h"
+#include "api/server-repo.h"
+
+class RepoDownloadInfo;
+class ApiError;
+
+class DownloadRepoDialog : public QDialog,
+ public Ui::DownloadRepoDialog
+{
+ Q_OBJECT
+public:
+ DownloadRepoDialog(const Account& account,
+ const ServerRepo& repo,
+ const QString& password,
+ QWidget *parent=0);
+
+ void setMergeWithExisting(const QString& localPath);
+ void setResyncMode();
+
+private slots:
+ void onOkBtnClicked();
+ void chooseDirAction();
+ void onDownloadRepoRequestSuccess(const RepoDownloadInfo& info);
+ void onDownloadRepoRequestFailed(const ApiError& error);
+ void switchMode();
+ void startResync();
+
+private:
+ Q_DISABLE_COPY(DownloadRepoDialog);
+
+ bool validateInputDirectory();
+ bool validateInputs();
+ void setAllInputsEnabled(bool enabled);
+ void setDirectoryText(const QString& path);
+ void updateSyncMode();
+
+ ServerRepo repo_;
+ Account account_;
+
+ // if we are in manual merge mode
+ bool manual_merge_mode_;
+ // used in auto mode, and always true in manual merge mode
+ bool sync_with_existing_;
+
+ // merge without question
+ bool merge_without_question_;
+
+ // save merge path
+ QString alternative_path_;
+
+ // Set to true when the dialog is used to resync a library, i.e. no user
+ // interaction needed.
+ bool resync_mode_;
+};
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QVBoxLayout>
+#include <QStackedLayout>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "loading-view.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "api/commit-details.h"
+#include "event-details-tree.h"
+#include "repo-service.h"
+#include "set-repo-password-dialog.h"
+
+#include "event-details-dialog.h"
+
+namespace {
+
+enum {
+ INDEX_LOADING_VIEW = 0,
+ INDEX_DETAILS_VIEW,
+};
+
+} // namespace
+
+EventDetailsDialog::EventDetailsDialog(const SeafEvent& event, QWidget *parent)
+ : QDialog(parent),
+ event_(event)
+{
+ setWindowTitle(tr("Modification Details"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ QStackedLayout *layout = new QStackedLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(layout);
+
+ loading_view_ = new LoadingView;
+ layout->addWidget(loading_view_);
+
+ tree_ = new EventDetailsListView(event);
+ model_ = new EventDetailsListModel(event);
+ tree_->setModel(model_);
+
+ layout->addWidget(tree_);
+
+ request_ = 0;
+
+ sendRequest();
+}
+
+void EventDetailsDialog::sendRequest()
+{
+ const Account& account = seafApplet->accountManager()->currentAccount();
+
+ if (request_) {
+ request_->deleteLater();
+ }
+
+ request_ = new GetCommitDetailsRequest(account, event_.repo_id, event_.commit_id);
+ connect(request_, SIGNAL(success(const CommitDetails&)),
+ this, SLOT(updateContent(const CommitDetails&)));
+ connect(request_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(getCommitDetailsFailed(const ApiError&)));
+ request_->send();
+}
+
+void EventDetailsDialog::updateContent(const CommitDetails& details)
+{
+ QStackedLayout *layout = (QStackedLayout *)this->layout();
+ layout->setCurrentIndex(INDEX_DETAILS_VIEW);
+
+ model_->setCommitDetails(details);
+}
+
+void EventDetailsDialog::getCommitDetailsFailed(const ApiError& error)
+{
+ ServerRepo repo = RepoService::instance()->getRepo(event_.repo_id);
+
+ if (!repo.isValid()) {
+ return;
+ }
+
+ if (repo.encrypted &&
+ error.type() == ApiError::HTTP_ERROR &&
+ error.httpErrorCode() == 400) {
+
+ SetRepoPasswordDialog dialog(repo, this);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ sendRequest();
+ } else {
+ reject();
+ }
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_EVENT_DETAILS_DIALOG_H
+#define SEAFILE_CLIENT_UI_EVENT_DETAILS_DIALOG_H
+
+#include <QDialog>
+#include "api/event.h"
+
+class GetCommitDetailsRequest;
+class CommitDetails;
+class EventDetailsListView;
+class EventDetailsListModel;
+class ApiError;
+
+// Display the commit details in a simple tree view
+class EventDetailsDialog : public QDialog {
+ Q_OBJECT
+public:
+ EventDetailsDialog(const SeafEvent& event, QWidget *parent=0);
+
+private slots:
+ void updateContent(const CommitDetails& details);
+ void getCommitDetailsFailed(const ApiError& error);
+
+private:
+ Q_DISABLE_COPY(EventDetailsDialog)
+
+ void sendRequest();
+
+ SeafEvent event_;
+
+ GetCommitDetailsRequest *request_;
+
+ EventDetailsListView *tree_;
+ EventDetailsListModel *model_;
+ QWidget *loading_view_;
+};
+
+#endif // SEAFILE_CLIENT_UI_EVENT_DETAILS_DIALOG_H
--- /dev/null
+#include <QtGlobal>
+#include <QFileInfo>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include "QtAwesome.h"
+
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "repo-service.h"
+
+#include "event-details-tree.h"
+namespace {
+const int kMarginLeft = 10;
+const int kMarginRight = 10;
+const int kPadding = 5;
+const int kFileIconHeight = 12;
+const int kFileItemHeight = 30;
+const int kFileItemWidth = 300;
+
+const int kFileNameWidth = 260;
+
+const int kFileNameFontSize = 14;
+
+const char *kFileItemBackgroundColor = "white";
+const char *kFileItemBackgroundColorHighlighted = "#F9E0C7";
+} // anonymous namespace
+
+/**
+ *
+ * status-icon file-path status-text
+ */
+
+void EventDetailsFileItemDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ QBrush backBrush;
+ bool selected = false;
+
+ if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+ backBrush = QColor(kFileItemBackgroundColorHighlighted);
+ selected = true;
+
+ } else {
+ backBrush = QColor(kFileItemBackgroundColor);
+ }
+
+ painter->save();
+ painter->fillRect(option.rect, backBrush);
+ painter->restore();
+
+ if (!index.isValid())
+ return;
+
+ const EventDetailsListModel* model = static_cast<const EventDetailsListModel*>(index.model());
+ EventDetailsFileItem *item = static_cast<EventDetailsFileItem*>(model->item(index.row()));
+
+ const int height = option.rect.height();
+ // get the device pixel radio from current painter device
+ int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ scale_factor = globalDevicePixelRatio();
+#endif // QT5
+ QPixmap icon(item->etype_icon().pixmap(QSize(kFileIconHeight, kFileIconHeight) * scale_factor).scaledToHeight(kFileIconHeight * scale_factor));
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ icon.setDevicePixelRatio(scale_factor);
+#endif // QT5
+ //
+ // draw status-icon
+ //
+
+ QPoint status_icon_pos = option.rect.topLeft() + QPoint(kMarginLeft, height / 2 - kFileIconHeight / 2);
+ painter->save();
+ painter->drawPixmap(status_icon_pos, icon);
+ painter->restore();
+
+ //
+ // draw file-path
+ //
+ const int file_path_width = static_cast<QWidget*>(parent())->width() - kFileItemWidth + kFileNameWidth;
+ QString path = item->path();
+ if (item->etype() == EventDetailsFileItem::FILE_RENAMED)
+ path = item->original_path() + " -> " + item->path();
+ painter->save();
+ QPoint file_name_pos = option.rect.topLeft() + QPoint(kMarginLeft + kFileIconHeight + kPadding, 0);
+ QRect file_name_rect(file_name_pos, QSize(file_path_width, height));
+ painter->setPen(QColor(item->etype_color()));
+ painter->setFont(changeFontSize(painter->font(), kFileNameFontSize));
+
+ painter->drawText(file_name_rect,
+ Qt::AlignLeft | Qt::AlignVCenter,
+ fitTextToWidth(path, option.font, file_path_width),
+ &file_name_rect);
+ painter->restore();
+}
+
+QSize EventDetailsFileItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ if (!index.isValid())
+ return QStyledItemDelegate::sizeHint(option, index);
+
+ return QSize(kFileItemWidth, kFileItemHeight);
+}
+
+EventDetailsFileItem::EventDetailsFileItem(const QString& path, EType etype, const QString& original_path)
+ : path_(path),
+ original_path_(original_path),
+ etype_(etype)
+{
+ // setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ setEditable(false);
+}
+
+QString EventDetailsFileItem::name() const
+{
+ return path_;
+}
+
+QString EventDetailsFileItem::etype_desc() const
+{
+ switch(etype_) {
+ case FILE_ADDED:
+ return QObject::tr("Added");
+ case FILE_DELETED:
+ return QObject::tr("Deleted");
+ case FILE_MODIFIED:
+ return QObject::tr("Modified");
+ case FILE_RENAMED:
+ return QObject::tr("Renamed");
+ case DIR_ADDED:
+ return QObject::tr("Added");
+ case DIR_DELETED:
+ return QObject::tr("Deleted");
+ };
+}
+
+QIcon EventDetailsFileItem::etype_icon() const
+{
+ switch(etype_) {
+ case FILE_ADDED:
+ return awesome->icon(icon_plus, QColor("#6CC644"));
+ case FILE_DELETED:
+ return awesome->icon(icon_minus, QColor("#BD2C00"));
+ case FILE_MODIFIED:
+ return awesome->icon(icon_pencil, QColor("#D0B44C"));
+ case FILE_RENAMED:
+ return awesome->icon(icon_arrow_right, QColor("#677A85"));
+ case DIR_ADDED:
+ return awesome->icon(icon_plus, QColor("#6CC644"));
+ case DIR_DELETED:
+ return awesome->icon(icon_minus, QColor("#BD2C00"));
+ };
+}
+
+const char* EventDetailsFileItem::etype_color() const
+{
+ switch(etype_) {
+ case FILE_ADDED:
+ return "#6CC644";
+ case FILE_DELETED:
+ return "#BD2C00";
+ case FILE_MODIFIED:
+ return "#D0B44C";
+ case FILE_RENAMED:
+ return "#677A85";
+ case DIR_ADDED:
+ return "#6CC644";
+ case DIR_DELETED:
+ return "#BD2C00";
+ };
+}
+
+bool EventDetailsFileItem::isFileOpenable() const
+{
+ return etype_ == FILE_ADDED ||
+ etype_ == FILE_MODIFIED ||
+ etype_ == FILE_RENAMED ||
+ etype_ == DIR_ADDED;
+}
+
+QVariant EventDetailsFileItem::data(int role) const
+{
+ if (role == Qt::DecorationRole) {
+ if (etype_ == DIR_ADDED || etype_ == DIR_DELETED) {
+ return QIcon(":/images/folder.png");
+ }
+ return QIcon(::getIconByFileName(name()));
+ } else if (role == Qt::DisplayRole) {
+ return name();
+ } else if (role == Qt::ToolTipRole) {
+ return path_;
+ } else {
+ return QVariant();
+ }
+}
+
+
+EventDetailsListView::EventDetailsListView(const SeafEvent& event, QWidget *parent)
+ : QListView(parent),
+ event_(event)
+{
+#if defined(Q_OS_MAC)
+ this->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+ setItemDelegate(new EventDetailsFileItemDelegate(this));
+
+ setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+ context_menu_ = new QMenu(this);
+ open_action_ = new QAction(tr("&Open"), this);
+ connect(open_action_, SIGNAL(triggered()),
+ this, SLOT(onOpen()));
+
+ open_in_file_browser_action_ = new QAction(tr("Open &parent folder"), this);
+ connect(open_in_file_browser_action_, SIGNAL(triggered()),
+ this, SLOT(onOpenInFileBrowser()));
+
+ context_menu_->addAction(open_action_);
+ context_menu_->addAction(open_in_file_browser_action_);
+}
+
+void EventDetailsListView::onItemDoubleClicked(const QModelIndex& index)
+{
+ QStandardItem *qitem = getFileItem(index);
+ if (!qitem) {
+ return;
+ }
+ EventDetailsFileItem *item = (EventDetailsFileItem *)qitem;
+ if (item->isFileOpenable()) {
+ RepoService::instance()->openLocalFile(event_.repo_id, item->path());
+ }
+}
+
+void EventDetailsListView::onOpen()
+{
+ if (!item_in_action_)
+ return;
+ RepoService::instance()->openLocalFile(event_.repo_id, item_in_action_->path());
+}
+
+void EventDetailsListView::onOpenInFileBrowser()
+{
+ if (!item_in_action_)
+ return;
+ RepoService::instance()->openFolder(event_.repo_id, QFileInfo(item_in_action_->path()).dir().path());
+}
+
+void EventDetailsListView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPoint position = event->pos();
+ const QModelIndex index = indexAt(position);
+ position = viewport()->mapToGlobal(position);
+
+ if (!index.isValid()) {
+ return;
+ }
+
+ const EventDetailsListModel* list_model = static_cast<EventDetailsListModel*>(model());
+ item_in_action_ = static_cast<EventDetailsFileItem*>(list_model->item(index.row()));
+ open_action_->setEnabled(item_in_action_->isFileOpenable());
+
+ context_menu_->exec(position); // synchronously
+}
+
+QStandardItem* EventDetailsListView::getFileItem(const QModelIndex& index)
+{
+ if (!index.isValid()) {
+ return NULL;
+ }
+ const EventDetailsListModel *model = (const EventDetailsListModel*)index.model();
+ QStandardItem *item = model->itemFromIndex(index);
+ return item;
+}
+
+EventDetailsListModel::EventDetailsListModel(const SeafEvent& event, QObject *parent)
+ : QStandardItemModel(parent),
+ event_(event)
+{
+}
+
+void EventDetailsListModel::setCommitDetails(const CommitDetails& details)
+{
+ clear();
+
+ details_ = details;
+
+ processEventCategory(details.added_files, tr("Added files"), EventDetailsFileItem::FILE_ADDED);
+ processEventCategory(details.deleted_files, tr("Deleted files"), EventDetailsFileItem::FILE_DELETED);
+ processEventCategory(details.modified_files, tr("Modified files"), EventDetailsFileItem::FILE_MODIFIED);
+
+ processEventCategory(details.added_dirs, tr("Added folders"), EventDetailsFileItem::DIR_ADDED);
+ processEventCategory(details.deleted_dirs, tr("Deleted folders"), EventDetailsFileItem::DIR_DELETED);
+
+ // renamed files is a list of (before rename, after rename) pair
+ for (int i = 0, n = details.renamed_files.size(); i < n; i++) {
+ EventDetailsFileItem *item = new EventDetailsFileItem(details.renamed_files[i].second, EventDetailsFileItem::FILE_RENAMED, details.renamed_files[i].first);
+ appendRow(item);
+ }
+}
+
+void EventDetailsListModel::processEventCategory(const std::vector<QString>& files,
+ const QString& desc,
+ EventDetailsFileItem::EType etype)
+{
+ if (files.empty()) {
+ return;
+ }
+
+ for (int i = 0, n = files.size(); i < n; i++) {
+ EventDetailsFileItem *item = new EventDetailsFileItem(files[i], etype);
+ appendRow(item);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_EVENT_DETAILS_TREE_H
+#define SEAFILE_CLIENT_UI_EVENT_DETAILS_TREE_H
+
+#include <QListView>
+#include <QStandardItemModel>
+#include <QStandardItem>
+#include <QStyledItemDelegate>
+#include <QIcon>
+
+#include "api/event.h"
+#include "api/commit-details.h"
+
+class QModelIndex;
+class QMenu;
+
+class EventDetailsFileItem : public QStandardItem {
+public:
+ enum EType {
+ FILE_ADDED = 0,
+ FILE_DELETED,
+ FILE_MODIFIED,
+ FILE_RENAMED,
+ DIR_ADDED,
+ DIR_DELETED
+ };
+
+ EventDetailsFileItem(const QString& path, EType etype, const QString& original_path = "");
+
+ virtual QVariant data(int role) const;
+
+ bool isFileOpenable() const;
+
+ // accessors
+ QString name() const;
+ const QString& path() const { return path_; }
+ const QString& original_path() const { return original_path_; }
+ EType etype() const { return etype_; }
+ QString etype_desc() const;
+ QIcon etype_icon() const;
+ const char* etype_color() const;
+
+private:
+
+ QString path_;
+ QString original_path_;
+ EType etype_;
+};
+
+class EventDetailsListView : public QListView {
+ Q_OBJECT
+public:
+ EventDetailsListView(const SeafEvent& event, QWidget *parent=0);
+
+private slots:
+ void onItemDoubleClicked(const QModelIndex& index);
+ void onOpen();
+ void onOpenInFileBrowser();
+
+private:
+ QStandardItem* getFileItem(const QModelIndex& index);
+
+ void contextMenuEvent(QContextMenuEvent * event);
+
+ SeafEvent event_;
+ QMenu* context_menu_;
+ QAction* open_action_;
+ QAction* open_in_file_browser_action_;
+ EventDetailsFileItem* item_in_action_;
+};
+
+class EventDetailsListModel : public QStandardItemModel {
+ Q_OBJECT
+public:
+ EventDetailsListModel(const SeafEvent& event, QObject *parent=0);
+
+ void setCommitDetails(const CommitDetails& details);
+
+private:
+ void processEventCategory(const std::vector<QString>& files,
+ const QString& desc,
+ EventDetailsFileItem::EType etype);
+
+ SeafEvent event_;
+ CommitDetails details_;
+};
+
+class EventDetailsFileItemDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+public:
+ explicit EventDetailsFileItemDelegate(QWidget *parent)
+ : QStyledItemDelegate(parent) {}
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+};
+
+#endif // SEAFILE_CLIENT_UI_EVENT_DETAILS_TREE_H
--- /dev/null
+#include <QPainter>
+#include <QApplication>
+#include <QPixmap>
+#include <QToolTip>
+#include <QLayout>
+#include <QDebug>
+
+#include "seafile-applet.h"
+#include "main-window.h"
+#include "events-service.h"
+#include "avatar-service.h"
+#include "event-details-dialog.h"
+#include "utils/paint-utils.h"
+#include "utils/utils.h"
+#include "api/event.h"
+
+#include "events-list-view.h"
+
+namespace {
+
+// new file activities ui
+/**
+ nick operation date
+ icon
+ description repo name
+ */
+
+/**
+ nick date
+ icon
+ description repo name
+ */
+
+const int kMarginLeft = 5;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 5;
+#ifdef Q_OS_MAC
+const int kExtraPadding = 5;
+#else
+const int kExtraPadding = 0;
+#endif
+
+const int kAvatarHeight = 40;
+const int kAvatarWidth = 40;
+//const int kNickWidth = 210;
+const int kNickHeight = 30;
+const int kOperationHeight = 18;
+const qreal kRadius = 3;
+
+const int kMarginBetweenAvatarAndNick = 10;
+const int kMarginBetweenNickAndOperation = 10;
+const int kVerticalMarginBetweenNickAndDesc = 3;
+
+const char *kNickColor = "#D8AC8F";
+const char *kNickColorHighlighted = "#D8AC8F";
+const char *kOperationColor = "white";
+const char *kOperRectFillColor = "#D8AC8F";
+const char *kRepoNameColor = "#D8AC8F";
+const char *kRepoNameColorHighlighted = "#D8AC8F";
+const char *kDescriptionColor = "#3F3F3F";
+const char *kDescriptionColorHighlighted = "#544D49";
+
+const int kNickFontSize = 16;
+const int kOperationFontSize = 13;
+const int kDescriptionFontSize = 13;
+const int kDescriptionHeight = 30;
+
+const char *kEventItemBackgroundColor = "white";
+const char *kEventItemBackgroundColorHighlighted = "#F9E0C7";
+
+const int kTimeWidth = 100;
+const int kTimeHeight = 30;
+const int kTimeFontSize = 13;
+
+const int kRepoNameWidth = 80;
+
+const char *kTimeColor = "#959595";
+const char *kTimeColorHighlighted = "#9D9B9A";
+
+const int kMarginBetweenNickAndTime = 10;
+const int kMarginBetweenOperationAndTime = 10;
+
+const int kMarginBetweenRepoNameAndDesc = 10;
+
+
+const char *kItemBottomBorderColor = "#EEE";
+
+} // namespace
+
+
+
+EventItem::EventItem(const SeafEvent& event)
+ : event_(event)
+{
+}
+
+EventItemDelegate::EventItemDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+}
+
+void EventItemDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ QBrush backBrush;
+ bool selected = false;
+
+ EventItem *item = getItem(index);
+ if (!item) {
+ return;
+ }
+
+ const SeafEvent& event = item->event();
+ QString operation_text = event.op_desc;
+ QString time_text = translateCommitTime(event.timestamp);
+
+ if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+ backBrush = QColor(kEventItemBackgroundColorHighlighted);
+ selected = true;
+
+ } else {
+ backBrush = QColor(kEventItemBackgroundColor);
+ }
+
+ painter->save();
+ painter->fillRect(option.rect, backBrush);
+ painter->restore();
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->setRenderHint(QPainter::HighQualityAntialiasing);
+
+ // get the device pixel radio from current painter device
+ double scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ scale_factor = globalDevicePixelRatio();
+#endif // QT5
+
+ // paint avatar
+ QImage avatar;
+ if (!event.anonymous) {
+ avatar = AvatarService::instance()->getAvatar(event.author);
+ }
+
+ QRect actualRect(0, 0, kAvatarWidth * scale_factor , kAvatarHeight * scale_factor);
+ avatar.scaled(actualRect.size());
+ QImage masked_image(actualRect.size(), QImage::Format_ARGB32_Premultiplied);
+ masked_image.fill(Qt::transparent);
+ QPainter mask_painter;
+ mask_painter.begin(&masked_image);
+ mask_painter.setRenderHint(QPainter::Antialiasing);
+ mask_painter.setRenderHint(QPainter::HighQualityAntialiasing);
+ mask_painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ mask_painter.setPen(Qt::NoPen);
+ mask_painter.setBrush(Qt::white);
+ mask_painter.drawEllipse(actualRect);
+ mask_painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ mask_painter.drawImage(actualRect, avatar);
+ mask_painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);
+ mask_painter.fillRect(actualRect, Qt::transparent);
+ mask_painter.end();
+ masked_image.setDevicePixelRatio(scale_factor);
+
+ QPoint avatar_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+ avatar_pos += option.rect.topLeft();
+ painter->save();
+ painter->drawImage(avatar_pos, masked_image);
+ painter->restore();
+
+ auto time_font = changeFontSize(painter->font(), kTimeFontSize);
+ auto nick_font = changeFontSize(painter->font(), kNickFontSize);
+ auto operation_font = changeFontSize(painter->font(), kOperationFontSize);
+ auto desc_font = changeFontSize(painter->font(), kDescriptionFontSize);
+ auto repo_name_font = time_font;
+
+ const int operation_width = ::textWidthInFont(operation_text, operation_font);
+ const int time_width = qMin(kTimeWidth, ::textWidthInFont(time_text, time_font));
+
+ int nick_width;
+ if (event.is_use_new_activities_api) {
+ nick_width = option.rect.width() - kMarginLeft - kAvatarWidth - kMarginBetweenAvatarAndNick
+ - kMarginBetweenNickAndOperation - operation_width - kMarginBetweenOperationAndTime
+ - time_width - kPadding * 2 - kMarginRight;
+ } else {
+ nick_width = option.rect.width() - kMarginLeft - kAvatarWidth - kMarginBetweenAvatarAndNick
+ - time_width - kMarginBetweenNickAndTime - kPadding * 2 - kMarginRight;
+ }
+
+ nick_width = qMin(nick_width, ::textWidthInFont(event.nick, nick_font));
+
+ // Paint nick name
+ QPoint nick_pos = avatar_pos + QPoint(kAvatarWidth + kMarginBetweenAvatarAndNick, 0);
+ QRect nick_rect(nick_pos, QSize(nick_width, kNickHeight));
+ painter->save();
+ painter->setPen(QColor(selected ? kNickColorHighlighted : kNickColor));
+ painter->setFont(nick_font);
+ painter->drawText(nick_rect,
+ Qt::AlignLeft | Qt::AlignTop,
+ fitTextToWidth(event.nick, option.font, nick_width),
+ &nick_rect);
+ painter->restore();
+
+ // Paint operation name
+ if (event.is_use_new_activities_api) {
+ QPoint operation_pos = nick_pos + QPoint(nick_width + kMarginBetweenNickAndOperation, 3);
+ QRect operation_rect(operation_pos, QSize(operation_width + 8, kOperationHeight));
+ painter->save();
+ QPainterPath path;
+ path.addRoundedRect(operation_rect, kRadius, kRadius);
+ painter->fillPath(path, QColor(kOperRectFillColor));
+
+ painter->setPen(QColor(kOperationColor));
+ painter->setFont(operation_font);
+ painter->drawText(operation_rect,
+ Qt::AlignCenter,
+ fitTextToWidth(operation_text, option.font, operation_width),
+ &operation_rect);
+ painter->restore();
+ }
+
+ // Paint event time
+ painter->save();
+ QPoint time_pos = option.rect.topRight() + QPoint(-time_width - kPadding - kMarginRight, kMarginTop + kPadding);
+ QRect time_rect(time_pos, QSize(time_width, kTimeHeight));
+ painter->setPen(QColor(selected ? kTimeColorHighlighted : kTimeColor));
+ painter->setFont(time_font);
+
+ painter->drawText(time_rect,
+ Qt::AlignRight | Qt::AlignTop,
+ time_text,
+ &time_rect);
+ painter->restore();
+
+ // Paint description
+ painter->save();
+
+ QString desc = event.desc;
+
+ int repo_name_width = qMin(kRepoNameWidth, ::textWidthInFont(event.repo_name, repo_name_font));
+
+ int desc_width = option.rect.width() - kMarginLeft - kAvatarWidth -
+ kMarginBetweenAvatarAndNick -
+ kMarginBetweenRepoNameAndDesc - repo_name_width -
+ kMarginRight - kPadding * 2;
+
+ const int desc_height = ::textHeightInFont(desc, desc_font) * 2;
+
+ // const QPoint event_desc_pos = option.rect.bottomLeft() + QPoint(nick_rect.left(), - desc_height - kExtraPadding - kMarginBottom);
+ const QPoint event_desc_pos = nick_rect.bottomLeft() + QPoint(0, kVerticalMarginBetweenNickAndDesc);
+
+ QRect event_desc_rect(event_desc_pos, QSize(desc_width, desc_height));
+ painter->setFont(desc_font);
+ painter->setPen(QColor(selected ? kDescriptionColorHighlighted : kDescriptionColor));
+
+ desc.replace(QChar('\n'), QChar(' '));
+ painter->drawText(event_desc_rect,
+ Qt::AlignLeft | Qt::AlignTop | Qt::TextWrapAnywhere,
+ // we have two lines
+ fitTextToWidth(desc, desc_font, desc_width * 2),
+ &event_desc_rect);
+ painter->restore();
+
+ // Paint repo name
+ painter->save();
+
+ repo_name_width += desc_width - event_desc_rect.width();
+ // if (index.row() == 1) {
+ // printf ("width diff = %d\n", desc_width - event_desc_rect.width());
+ // }
+
+ const int repo_name_height = ::textHeightInFont(event.repo_name, repo_name_font);
+ const QPoint event_repo_name_pos = option.rect.bottomRight() +
+ QPoint(-repo_name_width - kPadding - kMarginRight,
+ -repo_name_height - kExtraPadding - kMarginBottom);
+
+ QRect event_repo_name_rect(event_repo_name_pos, QSize(repo_name_width, kNickHeight));
+ painter->setFont(repo_name_font);
+ painter->setPen(QColor(selected ? kRepoNameColorHighlighted : kRepoNameColor));
+ painter->drawText(
+ event_repo_name_rect,
+ Qt::AlignRight | Qt::AlignTop | Qt::TextSingleLine,
+ fitTextToWidth(event.repo_name, repo_name_font, repo_name_width),
+ &event_repo_name_rect);
+ painter->restore();
+
+ // const EventsListModel *model = (const EventsListModel*)index.model();
+ //
+ // Draw the bottom border lines except for the last item (if the "load more" is present")
+ // We minus 2 here becase:
+ // 1) the row index starts from 0
+ // 2) we addded a row for the "load more" data in the end
+ // if (model->loadMoreIndex().isValid() && index.row() == model->rowCount() - 2) {
+ // return;
+ // }
+
+ painter->save();
+ painter->setPen(QPen(QColor(kItemBottomBorderColor), 1, Qt::SolidLine));
+ QPoint left = option.rect.bottomLeft();
+ left.setY(left.y() + 1);
+ QPoint right = option.rect.bottomRight();
+ right.setY(right.y() + 1);
+ painter->drawLine(left, right);
+ painter->restore();
+}
+
+QSize EventItemDelegate::sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ int height = kNickHeight + kDescriptionHeight + kPadding * 4 - kExtraPadding;
+ return QSize(option.rect.width(), height);
+}
+
+EventItem*
+EventItemDelegate::getItem(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return NULL;
+ }
+ const EventsListModel *model = (const EventsListModel*)index.model();
+ QStandardItem *qitem = model->itemFromIndex(index);
+ if (qitem->type() == EVENT_ITEM_TYPE) {
+ return (EventItem *)qitem;
+ } else {
+ return NULL;
+ }
+}
+
+EventsListView::EventsListView(QWidget *parent)
+ : QListView(parent)
+{
+ setItemDelegate(new EventItemDelegate);
+ connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+
+ setEditTriggers(QAbstractItemView::NoEditTriggers);
+}
+
+EventItem*
+EventsListView::getItem(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return NULL;
+ }
+ const EventsListModel *model = (const EventsListModel*)index.model();
+ QStandardItem *qitem = model->itemFromIndex(index);
+ if (qitem->type() == EVENT_ITEM_TYPE) {
+ return (EventItem *)qitem;
+ }
+ return NULL;
+}
+
+void EventsListView::onItemDoubleClicked(const QModelIndex& index)
+{
+ EventItem *item = getItem(index);
+ if (!item) {
+ return;
+ }
+
+ const SeafEvent& event = item->event();
+
+ if (!event.isDetailsDisplayable()) {
+ return;
+ }
+
+ EventDetailsDialog* dialog = new EventDetailsDialog(event, seafApplet->mainWindow());
+ dialog->setAttribute(Qt::WA_DeleteOnClose, true);
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+}
+
+bool EventsListView::viewportEvent(QEvent *event)
+{
+ if (event->type() != QEvent::ToolTip && event->type() != QEvent::WhatsThis) {
+ return QListView::viewportEvent(event);
+ }
+
+ QPoint global_pos = QCursor::pos();
+ QPoint viewport_pos = viewport()->mapFromGlobal(global_pos);
+ QModelIndex index = indexAt(viewport_pos);
+ if (!index.isValid()) {
+ return true;
+ }
+
+ EventItem *item = getItem(index);
+ if (!item) {
+ return true;
+ }
+
+ QRect item_rect = visualRect(index);
+
+ QString text = "<p style='white-space:pre'>";
+ text += item->event().desc;
+ text += "</p>";
+
+ QToolTip::showText(QCursor::pos(), text, viewport(), item_rect);
+
+ return true;
+}
+
+
+EventsListModel::EventsListModel(QObject *parent)
+ : QStandardItemModel(parent)
+{
+}
+
+const QModelIndex
+EventsListModel::updateEvents(const std::vector<SeafEvent>& events,
+ bool is_loading_more,
+ bool has_more)
+{
+ if (!is_loading_more) {
+ clear();
+ }
+ int i = 0, n = events.size();
+
+ EventItem *first_item = 0;
+
+ for (i = 0; i < n; i++) {
+ SeafEvent event = events[i];
+ EventItem *item = new EventItem(event);
+
+ appendRow(item);
+
+ if (!first_item) {
+ first_item = item;
+ }
+ }
+
+ if (has_more) {
+ QStandardItem *load_more_item = new QStandardItem();
+ appendRow(load_more_item);
+ load_more_index_ = load_more_item->index();
+ }
+
+ if (is_loading_more && first_item) {
+ return indexFromItem(first_item);
+ }
+
+ return QModelIndex();
+}
+
+void EventsListModel::onAvatarUpdated(const QString& email, const QImage& img)
+{
+ int i, n = rowCount();
+
+ for (i = 0; i < n; i++) {
+ QStandardItem *qitem = item(i);
+ if (qitem->type() != EVENT_ITEM_TYPE) {
+ return;
+ }
+ EventItem *item = (EventItem *)qitem;
+
+ if (item->event().author == email) {
+ QModelIndex index = indexFromItem(item);
+ emit dataChanged(index, index);
+ }
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_EVENTS_LIST_VIEW_H
+#define SEAFILE_CLIENT_UI_EVENTS_LIST_VIEW_H
+
+#include <vector>
+#include <QListView>
+#include <QStandardItem>
+#include <QStyledItemDelegate>
+#include <QModelIndex>
+
+#include "api/event.h"
+
+class QImage;
+class QEvent;
+
+class SeafEvent;
+
+enum {
+ EVENT_ITEM_TYPE = QStandardItem::UserType,
+};
+
+class EventItem : public QStandardItem {
+public:
+ EventItem(const SeafEvent& event);
+
+ virtual int type() const { return EVENT_ITEM_TYPE; }
+
+ const SeafEvent& event() const { return event_; }
+
+private:
+
+ SeafEvent event_;
+};
+
+class EventItemDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+public:
+ explicit EventItemDelegate(QObject *parent=0);
+
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+private:
+ void paintItem(QPainter *painter,
+ const QStyleOptionViewItem& opt,
+ const EventItem *item) const;
+
+ QSize sizeHintForItem(const QStyleOptionViewItem &option,
+ const EventItem *item) const;
+
+ EventItem* getItem(const QModelIndex &index) const;
+};
+
+class EventsListModel : public QStandardItemModel {
+ Q_OBJECT
+public:
+ EventsListModel(QObject *parent=0);
+
+ const QModelIndex updateEvents(const std::vector<SeafEvent>& events,
+ bool is_loading_more,
+ bool has_more);
+ const QModelIndex loadMoreIndex() const { return load_more_index_; }
+
+public slots:
+ void onAvatarUpdated(const QString& email, const QImage& img);
+
+private:
+ QModelIndex load_more_index_;
+};
+
+class EventsListView : public QListView {
+ Q_OBJECT
+public:
+ EventsListView(QWidget *parent=0);
+
+ void updateEvents(const std::vector<SeafEvent>& events, bool is_loading_more);
+
+ bool viewportEvent(QEvent *event);
+
+private slots:
+ void onItemDoubleClicked(const QModelIndex& index);
+
+private:
+ Q_DISABLE_COPY(EventsListView)
+
+ EventItem* getItem(const QModelIndex &index) const;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_EVENTS_LIST_VIEW_H
--- /dev/null
+#if !defined(Q_OS_WIN32)
+#include <sys/stat.h>
+#endif
+
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "init-seafile-dialog.h"
+#include <vector>
+
+#if defined(Q_OS_WIN32)
+#include <ShlObj.h>
+#include <shlwapi.h>
+#endif
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+QString get_largest_drive()
+{
+ wchar_t drives[MAX_PATH];
+ wchar_t *p, *largest_drive;
+ ULARGE_INTEGER free_space;
+ ULARGE_INTEGER largest_free_space;
+
+ largest_free_space.QuadPart = 0;
+ largest_drive = NULL;
+
+ GetLogicalDriveStringsW (sizeof(drives), drives);
+ for (p = drives; *p != L'\0'; p += wcslen(p) + 1) {
+ /* Skip floppy disk, network drive, etc */
+ if (GetDriveTypeW(p) != DRIVE_FIXED)
+ continue;
+
+ if (GetDiskFreeSpaceExW (p, &free_space, NULL, NULL)) {
+ if (free_space.QuadPart > largest_free_space.QuadPart) {
+ largest_free_space.QuadPart = free_space.QuadPart;
+ if (largest_drive != NULL) {
+ free (largest_drive);
+ }
+ largest_drive = wcsdup(p);
+ }
+
+ } else {
+ qDebug ("failed to GetDiskFreeSpaceEx(), GLE=%lu\n",
+ GetLastError());
+ }
+ }
+
+ QString ret;
+ if (largest_drive) {
+ ret = QString::fromStdWString(largest_drive);
+ free(largest_drive);
+ }
+
+ return ret;
+}
+
+QString getSystemDirectory()
+{
+ std::vector<wchar_t> path;
+ path.resize(MAX_PATH);
+
+ UINT len = ::GetSystemDirectoryW(&path[0], MAX_PATH);
+ path.resize(len);
+ if (len > MAX_PATH) {
+ len = ::GetSystemDirectoryW(&path[0], len);
+ }
+ return QString::fromWCharArray(&path[0], (int)len);
+}
+
+inline bool hasSameDrive(const QString& path_a, const QString &path_b)
+{
+ // to detect drive letter of a file, use QFileInfo::absoluteFilePath
+ // (D:\)
+ // On Windows this will always begin 'D:/' where D is a drive letter, except
+ // for network shares that are not mapped to a drive letter
+ // same driver letter?
+ if (path_a.length() < 3 || path_b.length() < 3)
+ return false;
+ if (path_a[0] != path_b[0])
+ return false;
+ if (path_a[1] != ':' || (path_a[2] != '/' && path_a[2] != '\\') ||
+ path_b[1] != ':' || (path_b[2] != '/' && path_b[2] != '\\'))
+ return false;
+ return true;
+}
+
+#endif
+
+
+} // namespace
+
+InitSeafileDialog::InitSeafileDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ setWindowTitle(tr("%1 Initialization").arg(getBrand()));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ connect(mChooseDirBtn, SIGNAL(clicked()), this, SLOT(chooseDir()));
+ connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkClicked()));
+ connect(mCancelBtn, SIGNAL(clicked()), this, SLOT(onCancelClicked()));
+
+ mTitle->setText(tr("Choose %1 folder").arg(getBrand()));
+ mCentralText->setText(
+ tr("Please choose a folder. We will create a %1 subfolder in it. "
+ "When you download a library, it will be saved there by default.")
+ .arg(getBrand()));
+ mLogo->setPixmap(QPixmap(":/images/seafile-32.png"));
+ mDirectory->setText(getInitialPath());
+
+ const QRect screen = QApplication::desktop()->screenGeometry();
+ move(screen.center() - this->rect().center());
+}
+
+QString InitSeafileDialog::getInitialPath()
+{
+#if defined(Q_OS_WIN32)
+ QString largest_drive = get_largest_drive();
+ QString home_path = QDir::home().absolutePath();
+ QString sys_path = getSystemDirectory();
+ if (hasSameDrive(largest_drive, sys_path) ||
+ hasSameDrive(largest_drive, home_path))
+ return home_path;
+
+ // work around with UTF-16 bug?
+ return QString::fromUtf8(largest_drive.toUtf8());
+#else
+ return QDir::home().path();
+#endif
+}
+
+void InitSeafileDialog::chooseDir()
+{
+ QString initial_path;
+
+ // On windows, set the initial path to the max volume, on linux/mac, set
+ // to the home direcotry.
+ QString dir = QFileDialog::getExistingDirectory(this, tr("Please choose a directory"),
+ getInitialPath(),
+ QFileDialog::ShowDirsOnly
+ | QFileDialog::DontResolveSymlinks);
+ if (dir.isEmpty())
+ return;
+
+ mDirectory->setText(dir);
+}
+
+void InitSeafileDialog::onOkClicked()
+{
+ QString path = mDirectory->text();
+ if (path.isEmpty()) {
+ seafApplet->warningBox(tr("Please choose a directory"), this);
+ return;
+ }
+
+ QDir dir(path);
+ if (!dir.exists()) {
+ seafApplet->warningBox(tr("The folder %1 does not exist").arg(path), this);
+ return;
+ }
+
+#if defined(Q_OS_WIN32)
+ QString data_dir_name = QString("%1/seafile-data").arg(getBrand());
+#else
+ QString data_dir_name = QString("%1/.seafile-data").arg(getBrand());
+#endif
+
+ dir.mkpath(data_dir_name);
+ QString seafile_dir = dir.filePath(data_dir_name);
+
+ // the .seafile-data Directory has set "read" rights for "others".
+ // if this Directory is "stolen", an attacker can access all files
+ // which are not in an encrypted file containe.
+#if !defined(Q_OS_WIN32)
+ int chmod_return_code = chmod(
+ toCStr(data_dir_name), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+ if (chmod_return_code < 0) {
+ qWarning("Modify the file \"%s\" permission error.",
+ toCStr(data_dir_name));
+ }
+#endif
+
+ emit seafileDirSet(seafile_dir);
+
+ accept();
+}
+
+void InitSeafileDialog::onCancelClicked()
+{
+ if (seafApplet->yesOrNoBox(
+ tr("Initialization is not finished. Really quit?"), this, false)) {
+ reject();
+ }
+}
+
+void InitSeafileDialog::closeEvent(QCloseEvent *event)
+{
+ if (seafApplet->yesOrNoBox(
+ tr("Initialization is not finished. Really quit?"), this, false)) {
+ QDialog::closeEvent(event);
+ return;
+ }
+ event->ignore();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_INIT_SEAFILE_DIALOG_H
+#define SEAFILE_CLIENT_INIT_SEAFILE_DIALOG_H
+
+#include <QDialog>
+#include "ui_init-seafile-dialog.h"
+
+class QCloseEvent;
+
+class InitSeafileDialog : public QDialog,
+ public Ui::InitSeafileDialog
+{
+ Q_OBJECT
+
+public:
+ InitSeafileDialog(QWidget *parent=0);
+ void closeEvent(QCloseEvent *event);
+
+private slots:
+ void onOkClicked();
+ void onCancelClicked();
+ void chooseDir();
+
+signals:
+ void seafileDirSet(const QString&);
+
+private:
+ QString getInitialPath();
+};
+
+#endif // SEAFILE_CLIENT_INIT_SEAFILE_DIALOG_H
--- /dev/null
+#include <cstdio>
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QTimer>
+#include <QPixmap>
+#include <QFile>
+#include <QFileInfo>
+#include <QCoreApplication>
+
+#include "seafile-applet.h"
+#include "utils/utils.h"
+#include "configurator.h"
+#include "settings-mgr.h"
+#include "api/requests.h"
+#include "api/api-error.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "rpc/clone-task.h"
+
+#include "init-vdrive-dialog.h"
+
+namespace {
+
+const int kCheckDownloadInterval = 2000;
+
+} // namespace
+
+
+InitVirtualDriveDialog::InitVirtualDriveDialog(const Account& account, QWidget *parent)
+ : QDialog(parent),
+ account_(account)
+{
+ setupUi(this);
+ mLogo->setPixmap(QPixmap(":/images/seafile-32.png"));
+ setWindowTitle(tr("Download Default Library"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ mStatusText->setText(
+ tr("%1 organizes files by libraries.\nDo you like to download your "
+ "default library?").arg(getBrand()));
+ setStatusIcon(":/images/download-48.png");
+
+ create_default_repo_req_ = NULL;
+ download_default_repo_req_ = NULL;
+
+ check_download_timer_ = NULL;
+ connect(mYesBtn, SIGNAL(clicked()), this, SLOT(start()));
+ connect(mNoBtn, SIGNAL(clicked()), this, SLOT(onCancel()));
+
+ mRunInBackgroundBtn->setVisible(false);
+ mFinishBtn->setVisible(false);
+ mOpenBtn->setVisible(false);
+}
+
+void InitVirtualDriveDialog::start()
+{
+ // mYesBtn->setEnabled(false);
+ // mNoBtn->setEnabled(false);
+ mYesBtn->setVisible(false);
+ mNoBtn->setVisible(false);
+ getDefaultRepo();
+}
+
+void InitVirtualDriveDialog::onCancel()
+{
+ reject();
+}
+
+void InitVirtualDriveDialog::getDefaultRepo()
+{
+ setStatusText(tr("Checking your default library..."));
+ get_default_repo_req_ = new GetDefaultRepoRequest(account_);
+
+ connect(get_default_repo_req_, SIGNAL(success(bool, const QString&)),
+ this, SLOT(onGetDefaultRepoSuccess(bool, const QString&)));
+
+ connect(get_default_repo_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetDefaultRepoFailure(const ApiError&)));
+
+ get_default_repo_req_->send();
+}
+
+void InitVirtualDriveDialog::createDefaultRepo()
+{
+ setStatusText(tr("Creating the default library..."));
+ create_default_repo_req_ = new CreateDefaultRepoRequest(account_);
+
+ connect(create_default_repo_req_, SIGNAL(success(const QString&)),
+ this, SLOT(onCreateDefaultRepoSuccess(const QString&)));
+
+ connect(create_default_repo_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onCreateDefaultRepoFailure(const ApiError&)));
+
+ create_default_repo_req_->send();
+}
+
+void InitVirtualDriveDialog::startDownload(const QString& repo_id)
+{
+ default_repo_id_ = repo_id;
+
+ LocalRepo repo;
+
+ seafApplet->rpcClient()->getLocalRepo(repo_id, &repo);
+ if (repo.isValid()) {
+ // This repo is already here
+ qDebug("The default library has already been downloaded");
+ default_repo_path_ = repo.worktree;
+ finish();
+ return;
+ }
+
+ download_default_repo_req_ = new DownloadRepoRequest(account_, repo_id, false);
+
+ connect(download_default_repo_req_, SIGNAL(success(const RepoDownloadInfo&)),
+ this, SLOT(onDownloadRepoSuccess(const RepoDownloadInfo&)));
+
+ connect(download_default_repo_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onDownloadRepoFailure(const ApiError&)));
+
+ download_default_repo_req_->send();
+}
+
+void InitVirtualDriveDialog::onGetDefaultRepoSuccess(bool exists, const QString& repo_id)
+{
+ if (!exists) {
+ createDefaultRepo();
+ } else {
+ startDownload(repo_id);
+ }
+}
+
+void InitVirtualDriveDialog::onGetDefaultRepoFailure(const ApiError& error)
+{
+ if (error.type() == ApiError::HTTP_ERROR && error.httpErrorCode() == 404) {
+ fail(tr("Failed to create default library:\n\n"
+ "The server version must be 2.1 or higher to support this."));
+ } else {
+ fail(tr("Failed to get default library:\n%1").arg(error.toString()));
+ }
+}
+
+
+void InitVirtualDriveDialog::onCreateDefaultRepoSuccess(const QString& repo_id)
+{
+ startDownload(repo_id);
+}
+
+void InitVirtualDriveDialog::onCreateDefaultRepoFailure(const ApiError& error)
+{
+ if (error.type() == ApiError::HTTP_ERROR && error.httpErrorCode() == 404) {
+ fail(tr("Failed to create default library:\n\n"
+ "The server version must be 2.1 or higher to support this."));
+ } else {
+ fail(tr("Failed to create default library:\n%1").arg(error.toString()));
+ }
+}
+
+void InitVirtualDriveDialog::onDownloadRepoSuccess(const RepoDownloadInfo& info)
+{
+ int ret;
+ QString worktree = seafApplet->configurator()->worktreeDir();
+ QString error;
+
+ ret = seafApplet->rpcClient()->downloadRepo(info.repo_id,
+ info.repo_version, info.repo_name,
+ worktree, info.token,
+ QString(), info.magic,
+ info.email, info.random_key,
+ info.enc_version, info.more_info,
+ &error);
+
+ if (ret < 0) {
+ fail(tr("Failed to download default library:\n %1").arg(error));
+ } else {
+ check_download_timer_ = new QTimer(this);
+ connect(check_download_timer_, SIGNAL(timeout()), this, SLOT(checkDownloadProgress()));
+ check_download_timer_->start(kCheckDownloadInterval);
+
+ setStatusText(tr("Downloading default library..."));
+
+ mRunInBackgroundBtn->setVisible(true);
+ connect(mRunInBackgroundBtn, SIGNAL(clicked()), this, SLOT(hide()));
+ }
+}
+
+void InitVirtualDriveDialog::onDownloadRepoFailure(const ApiError& error)
+{
+ fail(tr("Failed to download default library:\n%1").arg(error.toString()));
+}
+
+void InitVirtualDriveDialog::openVirtualDisk()
+{
+ QDesktopServices::openUrl(QUrl::fromLocalFile(default_repo_path_));
+ accept();
+}
+
+void InitVirtualDriveDialog::finish()
+{
+ QString msg = tr("The default library has been downloaded.\n"
+ "You can click the \"Open\" button to view it.");
+ setStatusText(msg);
+ setStatusIcon(":/images/sync/done@2x.png");
+
+ mFinishBtn->setVisible(true);
+ mOpenBtn->setVisible(true);
+
+ connect(mFinishBtn, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(mOpenBtn, SIGNAL(clicked()), this, SLOT(openVirtualDisk()));
+}
+
+void InitVirtualDriveDialog::fail(const QString& reason)
+{
+ ensureVisible();
+
+ setStatusText(reason);
+ mFinishBtn->setVisible(true);
+ connect(mFinishBtn, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+void InitVirtualDriveDialog::checkDownloadProgress()
+{
+ // First check for error
+ std::vector<CloneTask> tasks;
+ if (seafApplet->rpcClient()->getCloneTasks(&tasks) < 0) {
+ return;
+ }
+
+ CloneTask task;
+ for (size_t i = 0; i < tasks.size(); i++) {
+ if (tasks[i].repo_id == default_repo_id_) {
+ task = tasks[i];
+ break;
+ }
+ }
+
+ if (!task.isValid()) {
+ return;
+ }
+
+ if (task.state != "done" && task.state != "error") {
+ return;
+ }
+
+ check_download_timer_->stop();
+
+ mRunInBackgroundBtn->setVisible(false);
+ ensureVisible();
+
+ if (task.state == "error") {
+ fail(tr("Error when downloading the default library: %1").arg(task.error_str));
+ return;
+ }
+
+ // Download is finished.
+ LocalRepo repo;
+ seafApplet->rpcClient()->getLocalRepo(default_repo_id_, &repo);
+ default_repo_path_ = repo.worktree;
+ finish();
+}
+
+
+void InitVirtualDriveDialog::setStatusText(const QString& status)
+{
+ mStatusText->setText(status);
+}
+
+void InitVirtualDriveDialog::setStatusIcon(const QString& path)
+{
+ mStatusIcon->setPixmap(QPixmap(path));
+}
+
+void InitVirtualDriveDialog::ensureVisible()
+{
+ show();
+ raise();
+ activateWindow();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_INIT_VDRIVE_DIALOG_H
+#define SEAFILE_CLIENT_INIT_VDRIVE_DIALOG_H
+
+#include <QDialog>
+#include "ui_init-vdrive-dialog.h"
+#include "account.h"
+#include "api/requests.h"
+
+class LocalRepo;
+class QTimer;
+
+class InitVirtualDriveDialog : public QDialog,
+ public Ui::InitVirtualDriveDialog
+{
+ Q_OBJECT
+public:
+ InitVirtualDriveDialog(const Account& account, QWidget *parent=0);
+
+private slots:
+ void onGetDefaultRepoSuccess(bool exists, const QString& repo_id);
+ void onGetDefaultRepoFailure(const ApiError& error);
+ void onCreateDefaultRepoSuccess(const QString& repo_id);
+ void onCreateDefaultRepoFailure(const ApiError& error);
+ void onDownloadRepoSuccess(const RepoDownloadInfo& info);
+ void onDownloadRepoFailure(const ApiError& error);
+ void checkDownloadProgress();
+ void start();
+ void onCancel();
+ void openVirtualDisk();
+
+private:
+ Q_DISABLE_COPY(InitVirtualDriveDialog)
+
+ void getDefaultRepo();
+ void startDownload(const QString& repo_id);
+ void createLoadingView();
+ void createDefaultRepo();
+ void setStatusText(const QString& status);
+ void setStatusIcon(const QString& path);
+ void ensureVisible();
+ void finish();
+ void fail(const QString& reason);
+
+ GetDefaultRepoRequest *get_default_repo_req_;
+ CreateDefaultRepoRequest *create_default_repo_req_;
+ DownloadRepoRequest *download_default_repo_req_;
+
+ QString default_repo_id_;
+ QString default_repo_path_;
+
+ Account account_;
+
+ QTimer *check_download_timer_;
+};
+
+#endif // SEAFILE_CLIENT_INIT_VDRIVE_DIALOG_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "loading-view.h"
+
+LoadingView::LoadingView(QWidget *parent)
+ : QLabel(parent)
+{
+ gif_ = new QMovie(":/images/loading-spinner.gif");
+ gif_->setScaledSize(QSize(24, 24));
+ gif_->setParent(this);
+ setMovie(gif_);
+ setAlignment(Qt::AlignCenter);
+}
+
+void LoadingView::showEvent(QShowEvent *event)
+{
+ gif_->start();
+ QWidget::showEvent(event);
+}
+
+void LoadingView::hideEvent(QHideEvent *event)
+{
+ gif_->stop();
+ QWidget::hideEvent(event);
+}
+
+void LoadingView::setQssStyleForTab()
+{
+ static const char *kLoadingViewQss = "border: 0; margin: 0;"
+ "border-top: 1px solid #DCDCDE;"
+ "background-color: #F5F5F7;";
+
+ setStyleSheet(kLoadingViewQss);
+}
+
+LoadMoreButton::LoadMoreButton(QWidget *parent)
+ : QWidget(parent)
+{
+ load_more_btn_ = new QToolButton;
+ load_more_btn_->setObjectName("loadMoreBtn");
+ load_more_btn_->setText(tr("load more"));
+ btn_layout_ = new QHBoxLayout(this);
+ btn_layout_->addWidget(load_more_btn_, Qt::AlignCenter);
+
+ loading_label_ = new LoadingView;
+
+ // Must set fill backgound because this button is used as an "index widget".
+ // See the doc of QAbstractItemView::setIndexWidget for details.
+ setAutoFillBackground(true);
+
+ connect(load_more_btn_, SIGNAL(clicked()),
+ this, SLOT(onBtnClicked()));
+}
+
+void LoadMoreButton::onBtnClicked()
+{
+ load_more_btn_->hide();
+
+ btn_layout_->addWidget(loading_label_, Qt::AlignCenter);
+
+ emit clicked();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_LOADING_VIEW_H_
+#define SEAFILE_CLIENT_LOADING_VIEW_H_
+
+#include <QWidget>
+#include <QToolButton>
+#include <QLabel>
+
+class QMovie;
+class QShowEvent;
+class QHideEvent;
+class QHBoxLayout;
+
+class LoadingView : public QLabel {
+ Q_OBJECT
+public:
+ LoadingView(QWidget *parent=0);
+ void setQssStyleForTab();
+
+protected:
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
+
+private:
+ Q_DISABLE_COPY(LoadingView)
+
+ QMovie *gif_;
+};
+
+class LoadMoreButton : public QWidget {
+ Q_OBJECT
+public:
+ explicit LoadMoreButton(QWidget *parent=0);
+
+signals:
+ void clicked();
+
+private slots:
+ void onBtnClicked();
+
+private:
+ QHBoxLayout *btn_layout_;
+ QToolButton *load_more_btn_;
+ LoadingView *loading_label_;
+};
+
+#endif // SEAFILE_CLIENT_LOADING_VIEW_H_
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QtNetwork>
+#include <QStringList>
+#include <QSettings>
+
+#include "settings-mgr.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "login-dialog.h"
+#include "utils/utils.h"
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+#include "shib/shib-login-dialog.h"
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+namespace {
+
+const char *kUsedServerAddresses = "UsedServerAddresses";
+const char *const kPreconfigureServerAddr = "PreconfigureServerAddr";
+const char *const kPreconfigureServerAddrOnly = "PreconfigureServerAddrOnly";
+const char *const kPreconfigureShibbolethLoginUrl = "PreconfigureShibbolethLoginUrl";
+
+// 1. Returned by the server "X-Seafile-OTP: required" when login (if the user has 2FA enabled)
+// 2. The client would send this header, e.g. "X-Seafile-OTP: 123456" when login again
+const char *const kSeafileOTPHeader = "X-SEAFILE-OTP";
+// This header tells sever to remember this device and do not ask this
+// device for 2fa token in the next 90 days. The server would return a
+// "S2FA" token which should be saved by the device.
+const char *const kRememberDeviceHeader = "X-SEAFILE-2FA-TRUST-DEVICE";
+// 1. The "S2FA" token returned by the server when "X-SEAFILE-2FA-TRUST-DEVICE: 1" is used to login
+// 2. The client should send this device when login again so the server won't ask it for the 2FA token.
+const char *const kTwofactorHeader = "X-SEAFILE-S2FA";
+
+const char *const kSchemeHTTPS = "https";
+
+QStringList getUsedServerAddresses()
+{
+ QSettings settings;
+ settings.beginGroup(kUsedServerAddresses);
+ QStringList retval = settings.value("main").toStringList();
+ settings.endGroup();
+ QString preconfigure_addr = seafApplet->readPreconfigureExpandedString(kPreconfigureServerAddr);
+ if (!preconfigure_addr.isEmpty() && !retval.contains(preconfigure_addr)) {
+ retval.push_back(preconfigure_addr);
+ }
+ return retval;
+}
+
+void saveUsedServerAddresses(const QString &new_address)
+{
+ QSettings settings;
+ settings.beginGroup(kUsedServerAddresses);
+ QStringList list = settings.value("main").toStringList();
+ // put the last used address to the front
+ list.removeAll(new_address);
+ list.insert(0, new_address);
+ settings.setValue("main", list);
+ settings.endGroup();
+}
+
+} // namespace
+
+LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+ setWindowTitle(tr("Add an account"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ request_ = NULL;
+ account_info_req_ = NULL;
+ is_remember_device_ = false;
+
+ mStatusText->setText("");
+ mLogo->setPixmap(QPixmap(":/images/seafile-32.png"));
+ QString preconfigure_addr = seafApplet->readPreconfigureExpandedString(kPreconfigureServerAddr);
+ if (seafApplet->readPreconfigureEntry(kPreconfigureServerAddrOnly).toBool() && !preconfigure_addr.isEmpty()) {
+ mServerAddr->setMaxCount(1);
+ mServerAddr->insertItem(0, preconfigure_addr);
+ mServerAddr->setCurrentIndex(0);
+ mServerAddr->setEditable(false);
+ } else {
+ mServerAddr->addItems(getUsedServerAddresses());
+ mServerAddr->clearEditText();
+ }
+ mServerAddr->setAutoCompletion(false);
+
+ mAutomaticLogin->setCheckState(Qt::Checked);
+
+ QString computerName = seafApplet->settingsManager()->getComputerName();
+ mComputerName->setText(computerName);
+
+ connect(mSubmitBtn, SIGNAL(clicked()), this, SLOT(doLogin()));
+
+ const QRect screen = QApplication::desktop()->screenGeometry();
+ move(screen.center() - this->rect().center());
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+ setupShibLoginLink();
+#else
+ mShibLoginLink->hide();
+#endif
+}
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+void LoginDialog::setupShibLoginLink()
+{
+ QString txt = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("Single Sign On"));
+ mShibLoginLink->setText(txt);
+ connect(mShibLoginLink, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(loginWithShib()));
+}
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+void LoginDialog::initFromAccount(const Account& account)
+{
+ setWindowTitle(tr("Re-login"));
+ mTitle->setText(tr("Re-login"));
+ mServerAddr->setMaxCount(1);
+ mServerAddr->insertItem(0, account.serverUrl.toString());
+ mServerAddr->setCurrentIndex(0);
+ mServerAddr->setEditable(false);
+
+ mAutomaticLogin->setCheckState(account.isAutomaticLogin ? Qt::Checked : Qt::Unchecked);
+ mUsername->setText(account.username);
+ mPassword->setFocus(Qt::OtherFocusReason);
+}
+
+void LoginDialog::doLogin()
+{
+ if (!validateInputs()) {
+ return;
+ }
+ saveUsedServerAddresses(url_.toString());
+
+ mStatusText->setText(tr("Logging in..."));
+
+ disableInputs();
+
+ if (request_) {
+ request_->deleteLater();
+ }
+
+ request_ = new LoginRequest(url_, username_, password_, computer_name_);
+
+ if (!two_factor_auth_token_.isEmpty()) {
+ request_->setHeader(kSeafileOTPHeader, two_factor_auth_token_);
+ }
+
+ if (is_remember_device_) {
+ request_->setHeader(kRememberDeviceHeader, "1");
+ }
+
+ Account account = seafApplet->accountManager()->getAccountByHostAndUsername(url_.host(), username_);
+ if (account.hasS2FAToken()) {
+ request_->setHeader(kTwofactorHeader, account.s2fa_token);
+ }
+
+ connect(request_, SIGNAL(success(const QString&, const QString&)),
+ this, SLOT(loginSuccess(const QString&, const QString&)));
+
+ connect(request_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(loginFailed(const ApiError&)));
+
+ request_->send();
+}
+
+void LoginDialog::disableInputs()
+{
+ mServerAddr->setEnabled(false);
+ mUsername->setEnabled(false);
+ mPassword->setEnabled(false);
+ mSubmitBtn->setEnabled(false);
+ mComputerName->setEnabled(false);
+}
+
+void LoginDialog::enableInputs()
+{
+ mServerAddr->setEnabled(true);
+ mUsername->setEnabled(true);
+ mPassword->setEnabled(true);
+ mSubmitBtn->setEnabled(true);
+ mComputerName->setEnabled(true);
+}
+
+void LoginDialog::onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string)
+{
+ showWarning(tr("Network Error:\n %1").arg(error_string));
+ enableInputs();
+
+ mStatusText->setText("");
+}
+
+void LoginDialog::onSslErrors(QNetworkReply* reply, const QList<QSslError>& errors)
+{
+ const QSslCertificate &cert = reply->sslConfiguration().peerCertificate();
+ qDebug() << "\n= SslErrors =\n" << dumpSslErrors(errors);
+ qDebug() << "\n= Certificate =\n" << dumpCertificate(cert);
+
+ if (seafApplet->detailedYesOrNoBox(tr("<b>Warning:</b> The ssl certificate of this server is not trusted, proceed anyway?"),
+ dumpSslErrors(errors) + dumpCertificate(cert),
+ this,
+ false))
+ reply->ignoreSslErrors();
+}
+
+bool LoginDialog::validateInputs()
+{
+ QString serverAddr = mServerAddr->currentText();
+ QString protocol;
+ QUrl url;
+
+ if (serverAddr.size() == 0) {
+ showWarning(tr("Please enter the server address"));
+ return false;
+ } else {
+ if (!serverAddr.startsWith("http://") && !serverAddr.startsWith("https://")) {
+ showWarning(tr("%1 is not a valid server address").arg(serverAddr));
+ return false;
+ }
+
+ url = QUrl(serverAddr, QUrl::StrictMode);
+ if (!url.isValid()) {
+ showWarning(tr("%1 is not a valid server address").arg(serverAddr));
+ return false;
+ }
+ }
+
+ QString email = mUsername->text();
+ if (email.size() == 0) {
+ showWarning(tr("Please enter the username"));
+ return false;
+ }
+
+ if (mPassword->text().size() == 0) {
+ showWarning(tr("Please enter the password"));
+ return false;
+ }
+
+ QString computer_name = mComputerName->text().trimmed();
+ if (computer_name.size() == 0) {
+ showWarning(tr("Please enter the computer name"));
+ return false;
+ }
+
+ url_ = url;
+ username_ = mUsername->text();
+ password_ = mPassword->text();
+ computer_name_ = mComputerName->text();
+
+ seafApplet->settingsManager()->setComputerName(computer_name_);
+
+ return true;
+}
+
+void LoginDialog::loginSuccess(const QString& token, const QString& s2fa_token)
+{
+ // Some server configures mandatory http -> https redirect. In
+ // such cases, we must update the server url to use https,
+ // otherwise libcurl (used by the daemon) would be have trouble
+ // dealing with it.
+ if (url_.scheme() != kSchemeHTTPS && request_->reply()->url().scheme() == kSchemeHTTPS) {
+ qWarning("Detected server %s redirects to https", toCStr(url_.toString()));
+ url_.setScheme(kSchemeHTTPS);
+ }
+ if (account_info_req_) {
+ account_info_req_->deleteLater();
+ }
+ account_info_req_ =
+ new FetchAccountInfoRequest(Account(url_, username_, token, 0, false, true, s2fa_token));
+ connect(account_info_req_, SIGNAL(success(const AccountInfo&)), this,
+ SLOT(onFetchAccountInfoSuccess(const AccountInfo&)));
+ connect(account_info_req_, SIGNAL(failed(const ApiError&)), this,
+ SLOT(onFetchAccountInfoFailed(const ApiError&)));
+ account_info_req_->send();
+}
+
+void LoginDialog::onFetchAccountInfoFailed(const ApiError& error)
+{
+ loginFailed(error);
+}
+
+void LoginDialog::loginFailed(const ApiError& error)
+{
+ switch (error.type()) {
+ case ApiError::SSL_ERROR:
+ onSslErrors(error.sslReply(), error.sslErrors());
+ break;
+ case ApiError::NETWORK_ERROR:
+ onNetworkError(error.networkError(), error.networkErrorString());
+ break;
+ case ApiError::HTTP_ERROR:
+ onHttpError(error.httpErrorCode());
+ default:
+ // impossible
+ break;
+ }
+}
+
+void LoginDialog::onFetchAccountInfoSuccess(const AccountInfo& info)
+{
+ Account account = account_info_req_->account();
+ // The user may use the username to login, but we need to store the email
+ // to account database
+ account.username = info.email;
+ account.isAutomaticLogin =
+ mAutomaticLogin->checkState() == Qt::Checked;
+ seafApplet->accountManager()->setCurrentAccount(account);
+ seafApplet->accountManager()->updateAccountInfo(account, info);
+ done(QDialog::Accepted);
+}
+
+void LoginDialog::onHttpError(int code)
+{
+ const QNetworkReply* reply = request_->reply();
+ if (reply->hasRawHeader(kSeafileOTPHeader) &&
+ QString(reply->rawHeader(kSeafileOTPHeader)) == "required") {
+ TwoFactorDialog two_factor_dialog;
+ if (two_factor_dialog.exec() == QDialog::Accepted) {
+ two_factor_auth_token_ = two_factor_dialog.getText();
+ is_remember_device_ = two_factor_dialog.rememberDeviceChecked();
+ }
+
+ if (!two_factor_auth_token_.isEmpty()) {
+ doLogin();
+ return;
+ }
+ } else {
+ QString err_msg, reason;
+ if (code == 400) {
+ reason = tr("Incorrect email or password");
+ } else if (code == 429) {
+ reason = tr("Logging in too frequently, please wait a minute");
+ } else if (code == 500) {
+ reason = tr("Internal Server Error");
+ }
+
+ if (reason.length() > 0) {
+ err_msg = tr("Failed to login: %1").arg(reason);
+ } else {
+ err_msg = tr("Failed to login");
+ }
+
+ showWarning(err_msg);
+ }
+
+ enableInputs();
+
+ mStatusText->setText("");
+}
+
+void LoginDialog::showWarning(const QString& msg)
+{
+ seafApplet->warningBox(msg, this);
+}
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+
+bool LoginDialog::getShibLoginUrl(const QString& last_shib_url, QUrl *url_out)
+{
+ QString server_addr = last_shib_url;
+ QUrl url;
+
+ while (true) {
+ bool ok;
+ server_addr =
+ seafApplet->getText(this,
+ tr("Single Sign On"),
+ tr("%1 Server Address").arg(getBrand()),
+ QLineEdit::Normal,
+ server_addr,
+ &ok);
+ server_addr = server_addr.trimmed();
+
+ // exit when user hits cancel button
+ if (!ok) {
+ return false;
+ }
+
+ if (server_addr.isEmpty()) {
+ showWarning(tr("Server address must not be empty").arg(server_addr));
+ continue;
+ }
+
+ if (!server_addr.startsWith("https://")) {
+ showWarning(tr("%1 is not a valid server address. It has to start with 'https://'").arg(server_addr));
+ continue;
+ }
+
+ url = QUrl(server_addr, QUrl::StrictMode);
+ if (!url.isValid()) {
+ showWarning(tr("%1 is not a valid server address").arg(server_addr));
+ continue;
+ }
+
+ *url_out = url;
+ return true;
+ }
+}
+
+void LoginDialog::loginWithShib()
+{
+ QString server_addr =
+ seafApplet->readPreconfigureEntry(kPreconfigureShibbolethLoginUrl)
+ .toString()
+ .trimmed();
+ if (!server_addr.isEmpty()) {
+ if (QUrl(server_addr).isValid()) {
+ qWarning("Using preconfigured shibboleth login url: %s\n",
+ toCStr(server_addr));
+ } else {
+ qWarning("Invalid preconfigured shibboleth login url: %s\n",
+ toCStr(server_addr));
+ server_addr = "";
+ }
+ }
+
+ QUrl url = server_addr;
+ if (server_addr.isEmpty()) {
+ // When we reach here, there is no preconfigured shibboleth login url,
+ // or the preconfigured url is invalid. So we ask the user for the url.
+ server_addr = seafApplet->settingsManager()->getLastShibUrl();
+ if (!getShibLoginUrl(server_addr, &url)) {
+ return;
+ }
+ }
+
+ seafApplet->settingsManager()->setLastShibUrl(url.toString());
+
+ ShibLoginDialog shib_dialog(url, mComputerName->text(), this);
+ if (shib_dialog.exec() == QDialog::Accepted) {
+ accept();
+ }
+}
+#endif // HAVE_SHIBBOLETH_SUPPORT
--- /dev/null
+#ifndef SEAFILE_CLIENT_LOGIN_DIALOG_H
+#define SEAFILE_CLIENT_LOGIN_DIALOG_H
+
+#include <QDialog>
+#include "ui_login-dialog.h"
+
+#include <QUrl>
+#include <QString>
+#include <QNetworkReply>
+
+#include "two-factor-dialog.h"
+
+class Account;
+class LoginRequest;
+class QNetworkReply;
+class QSslError;
+class ApiError;
+class FetchAccountInfoRequest;
+class AccountInfo;
+
+class LoginDialog : public QDialog,
+ public Ui::LoginDialog
+{
+ Q_OBJECT
+public:
+ LoginDialog(QWidget *parent=0);
+ void initFromAccount(const Account& account);
+
+private slots:
+ void doLogin();
+ void loginSuccess(const QString& token, const QString& s2fa_token);
+ void loginFailed(const ApiError& error);
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+ void loginWithShib();
+#endif // HAVE_SHIBBOLETH_SUPPORT
+ void onFetchAccountInfoSuccess(const AccountInfo& info);
+ void onFetchAccountInfoFailed(const ApiError&);
+
+private:
+ Q_DISABLE_COPY(LoginDialog);
+
+ enum LoginMode {
+ LOGIN_NORMAL = 0,
+ LOGIN_SHIB
+ };
+
+ void setupShibLoginLink();
+ bool validateInputs();
+ void disableInputs();
+ void enableInputs();
+ void showWarning(const QString& msg);
+
+ void onNetworkError(const QNetworkReply::NetworkError& error, const QString& error_string);
+ void onSslErrors(QNetworkReply *reply, const QList<QSslError>& errors);
+ void onHttpError(int code);
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+ bool getShibLoginUrl(const QString& last_shib_url, QUrl *url_out);
+#endif // HAVE_SHIBBOLETH_SUPPORT
+
+ QUrl url_;
+ QString username_;
+ QString password_;
+ QString computer_name_;
+ bool is_remember_device_;
+ LoginRequest *request_;
+ FetchAccountInfoRequest *account_info_req_;
+
+ QString two_factor_auth_token_;
+
+#ifdef HAVE_SHIBBOLETH_SUPPORT
+ LoginMode mode_;
+#endif // HAVE_SHIBBOLETH_SUPPORT
+};
+
+#endif // SEAFILE_CLIENT_LOGIN_DIALOG_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include "seafile-applet.h"
+#include "account-mgr.h"
+
+#include "logout-view.h"
+
+LogoutView::LogoutView(QWidget *parent)
+ : QWidget(parent)
+{
+ setObjectName("LogoutView");
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ setLayout(layout);
+
+ label_ = new QLabel;
+ label_->setAlignment(Qt::AlignCenter);
+
+ layout->addWidget(label_);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+ this, SLOT(onAccountChanged()));
+
+ onAccountChanged();
+}
+
+void LogoutView::setQssStyleForTab()
+{
+ static const char *kLogoutViewQss = "border: 0; margin: 0;"
+ "border-top: 1px solid #DCDCDE;"
+ "background-color: #F5F5F7;";
+
+ setStyleSheet(kLogoutViewQss);
+}
+
+void LogoutView::onAccountChanged()
+{
+ // disconnect current signal
+ disconnect(label_, SIGNAL(linkActivated(const QString&)), 0, 0);
+
+ QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>");
+
+ if (seafApplet->accountManager()->hasAccount()) {
+ connect(label_, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(reloginCurrentAccount()));
+ label_->setText(tr("You are logout. Please ") + link.arg(tr("login")));
+ } else {
+ connect(label_, SIGNAL(linkActivated(const QString&)),
+ seafApplet->accountManager(), SIGNAL(requireAddAccount()));
+ label_->setText(link.arg(tr("Add an account")));
+ }
+}
+
+void LogoutView::reloginCurrentAccount()
+{
+ Account account = seafApplet->accountManager()->accounts().front();
+ seafApplet->accountManager()->reloginAccount(account);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_LOGOUT_VIEW_H_
+#define SEAFILE_CLIENT_LOGOUT_VIEW_H_
+
+#include <QWidget>
+
+class QShowEvent;
+class QLabel;
+class Account;
+
+class LogoutView : public QWidget {
+ Q_OBJECT
+public:
+ LogoutView(QWidget *parent=0);
+ void setQssStyleForTab();
+
+private slots:
+ void onAccountChanged();
+ void reloginCurrentAccount();
+
+private:
+ Q_DISABLE_COPY(LogoutView)
+ QLabel *label_;
+};
+
+#endif // SEAFILE_CLIENT_LOGOUT_VIEW_H_
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QApplication>
+#include <QDesktopServices>
+#include <QFile>
+#include <QTextStream>
+#include <QDir>
+#include <QCoreApplication>
+
+#include <QDialog>
+#include <QTabBar>
+#include <QVBoxLayout>
+
+#include "cloud-view.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "tray-icon.h"
+#include "login-dialog.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "utils/utils-win.h"
+#include "filebrowser/auto-update-mgr.h"
+
+#include "main-window.h"
+
+namespace {
+
+enum WIDGET_INDEX {
+ INDEX_CLOUD_VIEW = 0,
+ INDEX_LOCAL_VIEW
+};
+
+const int kMinimumTopMargin = 20;
+const int kPreferredTopMargin = 150;
+
+const int kMinimumRightMargin = 100;
+const int kPreferredRightMargin = 150;
+
+QSize getReasonableWindowSize(const QSize &in)
+{
+ QSize size;
+ const QRect screen = QApplication::desktop()->availableGeometry();
+ return QSize(qMin(in.width(), screen.width() - kMinimumRightMargin),
+ qMin(in.height(), screen.height() - kMinimumTopMargin));
+}
+
+// Detect if the pos is outside the screens.
+bool isOutsideScreens(const QRect &rect) {
+ QList<QScreen*> screens = QGuiApplication::screens();
+ for (int i = 0; i < screens.size(); ++i) {
+ if (screens[i]->availableGeometry().contains(rect))
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+MainWindow::MainWindow()
+{
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowTitle(getBrand());
+
+ // Qt::Tool hides the taskbar entry on windows
+ // setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
+
+ Qt::WindowFlags flags = Qt::Window | Qt::WindowSystemMenuHint;
+ if (shouldUseFramelessWindow()) {
+ flags |= Qt::FramelessWindowHint;
+ } else {
+ flags |= Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint |
+ Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint;
+ }
+
+ setWindowFlags(flags);
+
+ cloud_view_ = new CloudView;
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(cloud_view_);
+
+ QWidget *wrapper = new QWidget;
+ wrapper->setObjectName("mainWrapper");
+ wrapper->setLayout(layout);
+ if (shouldUseFramelessWindow()) {
+ setAttribute(Qt::WA_TranslucentBackground, true);
+ } else {
+ wrapper->setStyleSheet("QWidget#mainWrapper {border : 0; border-radius: 0px;}");
+ }
+
+ setCentralWidget(wrapper);
+
+ createActions();
+
+#if defined(Q_OS_MAC) && (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+ connect(qApp, SIGNAL(applicationStateChanged(Qt::ApplicationState)),
+ this, SLOT(checkShowWindow()));
+#endif
+}
+
+void MainWindow::hide()
+{
+ writeSettings();
+ QMainWindow::hide();
+}
+
+void MainWindow::closeEvent(QCloseEvent *event)
+{
+ event->accept();
+ hide();
+}
+
+bool MainWindow::event(QEvent *ev)
+{
+ bool ret = QMainWindow::event(ev);
+
+ if (isMinimized() && ev->type() == QEvent::WindowStateChange) {
+ QWindowStateChangeEvent *wev = (QWindowStateChangeEvent *)ev;
+ if (wev->oldState() != Qt::WindowMinimized) {
+ writeSettings();
+ }
+ }
+
+ if (ev->type() == QEvent::Hide) {
+ writeSettings();
+ }
+
+ return ret;
+}
+
+void MainWindow::changeEvent(QEvent *event)
+{
+ if (!shouldUseFramelessWindow()) {
+ QWidget::changeEvent(event);
+ }
+// #if defined(Q_OS_WIN32)
+// /*
+// * Solve the problem of restoring a minimized frameless window on Windows
+// * See http://stackoverflow.com/questions/18614661/how-to-not-hide-taskbar-item-during-using-hide
+// */
+// if(event->type() == QEvent::WindowStateChange) {
+// if(windowState() & Qt::WindowMinimized ) {
+// //do something after minimize
+// } else {
+// cloud_view_->hide();
+// cloud_view_->show();
+// }
+// }
+// #endif
+}
+
+void MainWindow::showEvent(QShowEvent *event)
+{
+ readSettings();
+#if defined(Q_OS_WIN32)
+ /*
+ * Another hack to Solve the problem of restoring a minimized frameless window on Windows
+ * See http://qt-project.org/forums/viewthread/7081
+ */
+ if (shouldUseFramelessWindow()) {
+ QApplication::postEvent(this, new QEvent(QEvent::UpdateRequest), Qt::LowEventPriority);
+ }
+#endif
+ QWidget::showEvent(event);
+
+}
+
+// handle osx's applicationShouldHandleReopen
+// QTBUG-10899 OS X: Add support for ApplicationState capability
+void MainWindow::checkShowWindow()
+{
+ // printf ("app inactive = %s\n", (qApp->applicationState() & Qt::ApplicationInactive) ? "yes" : "no");
+#if defined(Q_OS_MAC) && (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+ if (qApp->applicationState() & Qt::ApplicationActive) {
+ if (qApp->activeModalWidget() || qApp->activePopupWidget() || qApp->activeWindow())
+ return;
+ showWindow();
+ }
+#endif
+}
+
+void MainWindow::createActions()
+{
+ refresh_qss_action_ = new QAction(QIcon(":/images/toolbar/refresh-gray.png"), tr("Refresh"), this);
+ connect(refresh_qss_action_, SIGNAL(triggered()), this, SLOT(refreshQss()));
+}
+
+void MainWindow::keyPressEvent(QKeyEvent *event)
+{
+ if (event->key() == Qt::Key_F5) {
+ refreshQss();
+ return;
+ } else if (event->key() == Qt::Key_F6) {
+ AutoUpdateManager::instance()->dumpCacheStatus();
+ return;
+ }
+
+ // if (event->key() == Qt::Key_F6) {
+ // showTestDialog(this);
+ // return;
+ // }
+
+ QMainWindow::keyPressEvent(event);
+}
+
+void MainWindow::showWindow()
+{
+ showNormal();
+ show();
+ raise();
+ activateWindow();
+ // a hack with UIElement application
+#ifdef Q_OS_MAC
+ utils::mac::orderFrontRegardless(seafApplet->mainWindow()->winId());
+#endif
+}
+
+void MainWindow::refreshQss()
+{
+ seafApplet->refreshQss();
+}
+
+void MainWindow::writeSettings()
+{
+ QSettings settings;
+
+ settings.beginGroup("MainWindow");
+ settings.setValue("size", size());
+ settings.setValue("pos", pos());
+ settings.endGroup();
+}
+
+QPoint MainWindow::getDefaultPosition(const QSize& size)
+{
+ const QRect screen = QApplication::desktop()->availableGeometry();
+ const QPoint top_right = screen.topRight();
+
+ int extra_height = qMax(screen.height() - size.height(), kMinimumTopMargin) / 2;
+ int right_margin = rect().width() + qMin(kPreferredRightMargin, (int)(0.1 * screen.width()));
+ int top_margin = qMin(qMin(extra_height, kPreferredTopMargin), (int)(0.1 * screen.width()));
+
+ return QPoint(top_right.x() - right_margin, top_right.y() + top_margin);
+}
+
+void MainWindow::readSettings()
+{
+ QPoint pos;
+ // Default size of the main window from qt.css.
+ const QSize default_size(325, 585);
+ QSize size;
+ QSettings settings;
+ settings.beginGroup("MainWindow");
+
+ static bool first_show = true;
+
+ if (first_show && seafApplet->configurator()->firstUse()) {
+ size = default_size;
+ pos = getDefaultPosition(default_size);
+ } else {
+ size = settings.value("size").toSize();
+ if (!size.isValid()) {
+ size = default_size;
+ } else {
+ size = getReasonableWindowSize(size);
+ }
+
+ pos = settings.value("pos", getDefaultPosition(size)).toPoint();
+
+ // we don't want to be out of screen at least 1/10 size
+ if (isOutsideScreens(QRect(pos, size / 10))) {
+ pos = getDefaultPosition(size);
+ }
+ }
+
+ first_show = false;
+
+ move(pos);
+ resize(size);
+}
--- /dev/null
+#ifndef SEAFILE_MAINWINDOW_H
+#define SEAFILE_MAINWINDOW_H
+
+#include <QMainWindow>
+
+class QAction;
+class QToolBar;
+class QResizeEvent;
+class QSize;
+
+class CloudView;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+ void keyPressEvent(QKeyEvent *event);
+ void showWindow();
+ void hide();
+
+ void readSettings();
+ void writeSettings();
+
+protected:
+ void createActions();
+ bool event(QEvent *event);
+ void changeEvent(QEvent *event);
+
+private slots:
+ void refreshQss();
+ void closeEvent(QCloseEvent *event);
+ void showEvent(QShowEvent *event);
+ void checkShowWindow(); //dummy slot if qt version is lower than 5.2.0
+
+private:
+ Q_DISABLE_COPY(MainWindow)
+
+ QPoint getDefaultPosition(const QSize& size);
+
+ QAction *refresh_qss_action_;
+
+ // ToolBar
+ QToolBar *tool_bar_;
+
+ QTabWidget *main_widget_;
+
+ CloudView *cloud_view_;
+};
+
+#endif // SEAFILE_MAINWINDOW_H
--- /dev/null
+#include <QComboBox>
+#include <QCompleter>
+#include <QLineEdit>
+#include <QPainter>
+#include <QResizeEvent>
+#include <QStringList>
+#include <QStringListModel>
+#include <QDateTime>
+#include <QScrollBar>
+#include "api/api-error.h"
+#include "api/requests.h"
+#include "private-share-dialog.h"
+#include "seafile-applet.h"
+#include "utils/file-utils.h"
+#include "utils/utils.h"
+
+namespace
+{
+enum {
+ COLUMN_NAME = 0,
+ COLUMN_PERMISSION,
+ MAX_COLUMN,
+};
+
+enum {
+ INDEX_USER_NAME = 0,
+ INDEX_GROUP_NAME,
+};
+
+const int kPermissionColumnWidth = 150;
+const int kNameColumnWidth = 300;
+const int kDefaultColumnHeight = 40;
+const int kIndicatorIconWidth = 10;
+const int kIndicatorIconHeight = 8;
+
+const int kMarginLeft = 2;
+const int kMarginTop = 2;
+const int kPadding = 2;
+const int kMarginBetweenPermissionAndIndicator = 10;
+
+const QColor kSelectedItemBackgroundcColor("#F9E0C7");
+const QColor kItemBackgroundColor("white");
+const QColor kItemBottomBorderColor("#f3f3f3");
+const QColor kItemColor("black");
+
+} // namespace
+
+PrivateShareDialog::PrivateShareDialog(const Account& account,
+ const QString& repo_id,
+ const QString& repo_name,
+ const QString& path,
+ bool to_group,
+ QWidget* parent)
+ : QDialog(parent),
+ account_(account),
+ repo_id_(repo_id),
+ repo_name_(repo_name),
+ path_(path),
+ to_group_(to_group),
+ request_in_progress_(false)
+{
+ setupUi(this);
+
+ setWindowTitle(
+ tr("Share %1")
+ .arg(path.length() <= 1 ? repo_name : ::getBaseName(path)));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+#if defined(Q_OS_MAC)
+ layout()->setContentsMargins(6, 6, 6, 6);
+ layout()->setSpacing(5);
+#endif
+
+ username_input_ = new QLineEdit(this);
+ username_input_->setObjectName("mUsernameInputBar");
+ groupname_input_ = new QComboBox(this);
+
+ mInputStack->insertWidget(INDEX_USER_NAME, username_input_);
+ mInputStack->insertWidget(INDEX_GROUP_NAME, groupname_input_);
+
+ if (to_group) {
+ mInputStack->setCurrentIndex(INDEX_GROUP_NAME);
+ groupname_input_->setEditable(true);
+ groupname_input_->clearEditText();
+ // The place holder text for the line editor of the combo box must be
+ // set
+ // after setEditable(true), because lineEdit() returns NULL before that.
+ groupname_input_->lineEdit()->setPlaceholderText(
+ tr("Enter the group name"));
+ groupname_input_->completer()->setCompletionMode(
+ QCompleter::PopupCompletion);
+ groupname_input_->clearEditText();
+ }
+ else {
+ mInputStack->setCurrentIndex(INDEX_USER_NAME);
+ username_input_->setPlaceholderText(tr("Enter user name or email address"));
+ }
+ mOkBtn->setEnabled(false);
+ mPermission->setCurrentIndex(0);
+ createTable();
+
+ if (to_group_) {
+ fetchGroupsForCompletion();
+ } else {
+ user_name_completer_.reset(new SeafileUserNameCompleter(account_, username_input_));
+ connect(lineEdit(), SIGNAL(returnPressed()), this, SLOT(onUserNameChoosed()));
+ getExistingShardItems();
+ }
+
+ connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+ connect(mCancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
+
+ connect(table_, SIGNAL(clicked(const QModelIndex&)), mStatusText,
+ SLOT(clear()));
+ connect(lineEdit(), SIGNAL(textChanged(const QString&)), mStatusText,
+ SLOT(clear()));
+ connect(lineEdit(), SIGNAL(textChanged(const QString&)), this,
+ SLOT(onNameInputEdited()));
+ connect(model_, SIGNAL(modelReset()), this, SLOT(selectFirstRow()));
+
+ adjustSize();
+ disableInputs();
+}
+
+void PrivateShareDialog::selectFirstRow()
+{
+ // for (int i = 0; i < model_->rowCount(); i++) {
+ // table_->openPersistentEditor(model_->index(i, COLUMN_PERMISSION));
+ // }
+
+ // Select the first row of the table, so that the indicator would be
+ // painted, to tell the user the permission is editable.
+ if (!table_->currentIndex().isValid()) {
+ table_->setCurrentIndex(model_->index(0, 0));
+ }
+}
+
+void PrivateShareDialog::createTable()
+{
+ table_ = new SharedItemsTableView(this);
+ // table_->setEditTriggers(QAbstractItemView::AllEditTriggers);
+ model_ = new SharedItemsTableModel(
+ to_group_ ? SHARE_TO_GROUP : SHARE_TO_USER, this);
+ table_->setModel(model_);
+ QVBoxLayout* vlayout = (QVBoxLayout*)mFrame->layout();
+ vlayout->insertWidget(1, table_);
+
+ table_->setItemDelegate(new SharedItemDelegate(this));
+ table_->setEditTriggers(QAbstractItemView::SelectedClicked);
+
+ // Overloaded signal for updating group share.
+ connect(model_, SIGNAL(updateShareItem(int, SharePermission)), this,
+ SLOT(onUpdateShareItem(int, SharePermission)));
+ // Overloaded signal for updating user share.
+ connect(model_, SIGNAL(updateShareItem(const SeafileUser&, SharePermission)),
+ this, SLOT(onUpdateShareItem(const SeafileUser&, SharePermission)));
+
+ // Overloaded signal for removing group share.
+ connect(model_, SIGNAL(removeShareItem(int, SharePermission)), this,
+ SLOT(onRemoveShareItem(int, SharePermission)));
+ // Overloaded signal for removing user share.
+ connect(model_, SIGNAL(removeShareItem(const SeafileUser&, SharePermission)),
+ this, SLOT(onRemoveShareItem(const SeafileUser&, SharePermission)));
+}
+
+void PrivateShareDialog::onNameInputEdited()
+{
+ if (to_group_) {
+ mOkBtn->setEnabled(!lineEdit()->text().trimmed().isEmpty());
+ } else {
+ // We only enable the confirm button after the user chooses an candidate
+ // from the completion list.
+ mOkBtn->setEnabled(false);
+ }
+}
+
+void PrivateShareDialog::fetchGroupsForCompletion()
+{
+ fetch_groups_request_.reset(new FetchGroupsRequest(account_));
+ fetch_groups_request_->send();
+ connect(fetch_groups_request_.data(),
+ SIGNAL(success(const QList<SeafileGroup>&)),
+ this, SLOT(onFetchGroupsSuccess(const QList<SeafileGroup>&)));
+ connect(fetch_groups_request_.data(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onFetchContactsFailed(const ApiError&)));
+}
+
+void PrivateShareDialog::onUpdateShareItem(int group_id,
+ SharePermission permission)
+{
+ request_.reset(new PrivateShareRequest(account_, repo_id_, path_, SeafileUser(),
+ group_id, permission, SHARE_TO_GROUP,
+ PrivateShareRequest::UPDATE_SHARE));
+
+ connect(request_.data(), SIGNAL(success()), this,
+ SLOT(onUpdateShareSuccess()));
+ connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onUpdateShareFailed(const ApiError&)));
+
+ // disableInputs();
+ request_in_progress_ = true;
+ request_->send();
+}
+
+void PrivateShareDialog::onUpdateShareItem(const SeafileUser& user,
+ SharePermission permission)
+{
+ request_.reset(new PrivateShareRequest(account_, repo_id_, path_, user, 0,
+ permission, SHARE_TO_USER,
+ PrivateShareRequest::UPDATE_SHARE));
+
+ connect(request_.data(), SIGNAL(success()), this,
+ SLOT(onUpdateShareSuccess()));
+ connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onUpdateShareFailed(const ApiError&)));
+
+ // disableInputs();
+ request_in_progress_ = true;
+ request_->send();
+}
+
+void PrivateShareDialog::onUpdateShareSuccess()
+{
+ request_in_progress_ = false;
+ // seafApplet->messageBox(tr("Shared successfully"), this);
+ if (to_group_) {
+ GroupShareInfo info;
+ info.group = groups_by_id_[request_->groupId()];
+ info.permission = request_.data()->permission();
+ model_->addNewShareInfo(info);
+ table_->setCurrentIndex(model_->getIndexByGroup(info.group.id));
+ }
+ else {
+ UserShareInfo info;
+ info.user = request_.data()->user();
+ info.permission = request_.data()->permission();
+ model_->addNewShareInfo(info);
+ table_->setCurrentIndex(model_->getIndexByUser(info.user));
+ }
+ model_->shareOperationSuccess();
+ mStatusText->setText(tr("Updated successfully"));
+}
+
+void PrivateShareDialog::onUpdateShareFailed(const ApiError& error)
+{
+ request_in_progress_ = false;
+ showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
+ model_->shareOperationFailed(request_->shareOperation());
+}
+
+void PrivateShareDialog::onRemoveShareItem(int group_id,
+ SharePermission permission)
+{
+ request_.reset(new PrivateShareRequest(account_, repo_id_, path_, SeafileUser(),
+ group_id, permission, SHARE_TO_GROUP,
+ PrivateShareRequest::REMOVE_SHARE));
+
+ connect(request_.data(), SIGNAL(success()), this,
+ SLOT(onRemoveShareSuccess()));
+ connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onRemoveShareFailed(const ApiError&)));
+
+ // disableInputs();
+ request_in_progress_ = true;
+ request_->send();
+}
+
+void PrivateShareDialog::onRemoveShareSuccess()
+{
+ request_in_progress_ = false;
+ model_->shareOperationSuccess();
+ mStatusText->setText(tr("Removed successfully"));
+}
+
+void PrivateShareDialog::onRemoveShareFailed(const ApiError& error)
+{
+ request_in_progress_ = false;
+ showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
+ model_->shareOperationFailed(request_->shareOperation());
+}
+
+void PrivateShareDialog::onRemoveShareItem(const SeafileUser& user,
+ SharePermission permission)
+{
+ request_.reset(new PrivateShareRequest(account_, repo_id_, path_, user, 0,
+ permission, SHARE_TO_USER,
+ PrivateShareRequest::REMOVE_SHARE));
+
+ connect(request_.data(), SIGNAL(success()), this,
+ SLOT(onRemoveShareSuccess()));
+ connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onRemoveShareFailed(const ApiError&)));
+
+ // disableInputs();
+ request_in_progress_ = true;
+ request_->send();
+}
+
+
+void PrivateShareDialog::onFetchGroupsSuccess(const QList<SeafileGroup>& groups)
+{
+ QStringList candidates;
+ foreach (const SeafileGroup& group, groups) {
+ candidates << group.name;
+ groups_by_id_[group.id] = group;
+ }
+
+ if (!candidates.isEmpty()) {
+ groupname_input_->addItems(candidates);
+ groupname_input_->clearEditText();
+ }
+
+ getExistingShardItems();
+}
+
+void PrivateShareDialog::getExistingShardItems()
+{
+ get_shared_items_request_.reset(
+ new GetPrivateShareItemsRequest(account_, repo_id_, path_));
+
+ connect(get_shared_items_request_.data(),
+ SIGNAL(success(const QList<GroupShareInfo>&,
+ const QList<UserShareInfo>&)),
+ this, SLOT(onGetSharedItemsSuccess(const QList<GroupShareInfo>&,
+ const QList<UserShareInfo>&)));
+ connect(get_shared_items_request_.data(), SIGNAL(failed(const ApiError&)),
+ this, SLOT(onGetSharedItemsFailed(const ApiError&)));
+
+ get_shared_items_request_->send();
+}
+
+void PrivateShareDialog::onGetSharedItemsSuccess(
+ const QList<GroupShareInfo>& group_shares,
+ const QList<UserShareInfo>& user_shares)
+{
+ model_->setShareInfo(group_shares, user_shares);
+ selectFirstRow();
+ enableInputs();
+}
+
+void PrivateShareDialog::onGetSharedItemsFailed(const ApiError& error)
+{
+ showWarning(tr("Failed to get share information of the folder"));
+ reject();
+}
+
+void PrivateShareDialog::onFetchContactsFailed(const ApiError& error)
+{
+ showWarning(tr("Failed to get your groups and contacts information"));
+ reject();
+}
+
+SharePermission PrivateShareDialog::currentPermission()
+{
+ return mPermission->currentIndex() == 0 ? READ_WRITE : READ_ONLY;
+}
+
+bool PrivateShareDialog::validateInputs()
+{
+ QString name = lineEdit()->text().trimmed();
+ if (name.isEmpty()) {
+ showWarning(to_group_ ? tr("Please enter the group name")
+ : tr("Please enter the username"));
+ return false;
+ }
+
+ SharePermission permission = currentPermission();
+
+ if (to_group_) {
+ SeafileGroup group;
+ bool found = false;
+ foreach (const SeafileGroup& g, groups_by_id_.values()) {
+ if (g.name == name) {
+ group = g;
+ found = true;
+ }
+ }
+ if (!found) {
+ showWarning(tr("No such group \"%1\"").arg(name));
+ return false;
+ }
+ if (model_->shareExists(group.id)) {
+ GroupShareInfo info = model_->shareInfo(group.id);
+ if (info.permission == permission) {
+ showWarning(tr("Already shared to group %1").arg(name));
+ }
+ return false;
+ }
+ }
+ else {
+ const SeafileUser& user = user_name_completer_->currentSelectedUser();
+ if (!user.isValid()) {
+ showWarning(tr("Please enter the username"));
+ return false;
+ }
+
+ if (model_->shareExists(user)) {
+ UserShareInfo info = model_->shareInfo(user);
+ if (info.permission == permission) {
+ showWarning(tr("Already shared to user %1").arg(name));
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+SeafileGroup PrivateShareDialog::findGroup(const QString& name)
+{
+ foreach (const SeafileGroup& group, groups_by_id_.values()) {
+ if (group.name == name) {
+ return group;
+ }
+ }
+ return SeafileGroup();
+}
+
+void PrivateShareDialog::onUserNameChoosed()
+{
+ const SeafileUser& user = user_name_completer_->currentSelectedUser();
+ if (user.isValid()) {
+ mOkBtn->setEnabled(true);
+ }
+}
+
+void PrivateShareDialog::onOkBtnClicked()
+{
+ if (!validateInputs()) {
+ return;
+ }
+ if (request_in_progress_) {
+ showWarning(tr("The previous operation is still in progres"));
+ return;
+ }
+
+ // disableInputs();
+ SeafileGroup group;
+ SeafileUser user;
+ QString name = lineEdit()->text().trimmed();
+ if (to_group_) {
+ group = findGroup(name);
+ }
+ else {
+ user = user_name_completer_->currentSelectedUser();
+ }
+ request_.reset(new PrivateShareRequest(
+ account_, repo_id_, path_, user, group.id, currentPermission(),
+ to_group_ ? SHARE_TO_GROUP : SHARE_TO_USER,
+ PrivateShareRequest::ADD_SHARE));
+
+ connect(request_.data(), SIGNAL(success()), this, SLOT(onShareSuccess()));
+
+ connect(request_.data(), SIGNAL(failed(const ApiError&)), this,
+ SLOT(onShareFailed(const ApiError&)));
+
+ request_in_progress_ = true;
+ request_->send();
+
+ if (to_group_) {
+ GroupShareInfo info;
+ info.group = group;
+ info.permission = currentPermission();
+ model_->addNewShareInfo(info);
+ }
+ else {
+ UserShareInfo info;
+ info.user = user;
+ info.permission = currentPermission();
+ model_->addNewShareInfo(info);
+ }
+}
+
+void PrivateShareDialog::disableInputs()
+{
+ toggleInputs(false);
+}
+
+void PrivateShareDialog::enableInputs()
+{
+ toggleInputs(true);
+}
+
+void PrivateShareDialog::toggleInputs(bool enabled)
+{
+ groupname_input_->setEnabled(enabled);
+ username_input_->setEnabled(enabled);
+ mOkBtn->setEnabled(enabled);
+ mCancelBtn->setEnabled(enabled);
+ mPermission->setEnabled(enabled);
+}
+
+void PrivateShareDialog::onShareSuccess()
+{
+ // seafApplet->messageBox(tr("Shared successfully"), this);
+ request_in_progress_ = false;
+ model_->shareOperationSuccess();
+ mStatusText->clear();
+}
+
+void PrivateShareDialog::onShareFailed(const ApiError& error)
+{
+ request_in_progress_ = false;
+ model_->shareOperationFailed(PrivateShareRequest::ADD_SHARE);
+ showWarning(tr("Share Operation Failed: %1").arg(error.toString()));
+}
+
+void PrivateShareDialog::showWarning(const QString& msg)
+{
+ seafApplet->warningBox(msg, this);
+}
+
+SharedItemsHeadView::SharedItemsHeadView(QWidget* parent)
+ : QHeaderView(Qt::Horizontal, parent)
+{
+ setDefaultAlignment(Qt::AlignLeft);
+ setStretchLastSection(false);
+ setCascadingSectionResizes(true);
+ setHighlightSections(false);
+ setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ setSectionResizeMode(QHeaderView::ResizeToContents);
+#else
+ setResizeMode(QHeaderView::ResizeToContents);
+#endif
+}
+
+QSize SharedItemsHeadView::sectionSizeFromContents(int index) const
+{
+ QSize size = QHeaderView::sectionSizeFromContents(index);
+ SharedItemsTableView* table = (SharedItemsTableView*)parent();
+ SharedItemsTableModel* model =
+ (SharedItemsTableModel*)(table->sourceModel());
+ if (model) {
+ size.setWidth(index == COLUMN_NAME ? model->nameColumnWidth()
+ : kPermissionColumnWidth);
+ }
+ return size;
+}
+
+SharedItemsTableView::SharedItemsTableView(QWidget* parent)
+ : QTableView(parent), source_model_(0)
+{
+ setHorizontalHeader(new SharedItemsHeadView(this));
+ verticalHeader()->hide();
+
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setSelectionMode(QAbstractItemView::SingleSelection);
+
+ setMouseTracking(true);
+ setShowGrid(false);
+ setContentsMargins(0, 5, 0, 5);
+ // setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+ horizontalScrollBar()->close();
+}
+
+void SharedItemsTableView::setModel(QAbstractItemModel* model)
+{
+ QTableView::setModel(model);
+ source_model_ = qobject_cast<SharedItemsTableModel*>(model);
+}
+
+void SharedItemsTableView::resizeEvent(QResizeEvent* event)
+{
+ QTableView::resizeEvent(event);
+ if (source_model_)
+ source_model_->onResize(event->size());
+}
+
+
+SharedItemsTableModel::SharedItemsTableModel(ShareType share_type,
+ QObject* parent)
+ : QAbstractTableModel(parent),
+ share_type_(share_type),
+ name_column_width_(kNameColumnWidth)
+{
+}
+
+
+int SharedItemsTableModel::columnCount(const QModelIndex& parent) const
+{
+ return MAX_COLUMN;
+}
+
+int SharedItemsTableModel::rowCount(const QModelIndex& parent) const
+{
+ return share_type_ == SHARE_TO_USER ? user_shares_.size()
+ : group_shares_.size();
+}
+
+QVariant SharedItemsTableModel::data(const QModelIndex& index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ if (role != Qt::DisplayRole && role != Qt::EditRole &&
+ role != Qt::SizeHintRole && role != Qt::ToolTipRole) {
+ return QVariant();
+ }
+
+ int row = index.row(), column = index.column();
+
+ if (role == Qt::EditRole && column != COLUMN_PERMISSION) {
+ return QVariant();
+ }
+
+ if (role == Qt::ToolTipRole) {
+ if (column == COLUMN_PERMISSION) {
+ return tr("Click to edit");
+ }
+ else {
+ if (isGroupShare()) {
+ const GroupShareInfo& info = group_shares_[row];
+ if (!info.group.owner.isEmpty()) {
+ return tr("Created by %1").arg(info.group.owner);
+ }
+ }
+ else {
+ return user_shares_[row].user.getDisplayEmail();
+ }
+ }
+ return QVariant();
+ }
+
+ // DisplayRole
+
+ if (role == Qt::SizeHintRole) {
+ QSize qsize(0, kDefaultColumnHeight);
+ if (column == COLUMN_NAME) {
+ qsize.setWidth(name_column_width_);
+ }
+ else {
+ qsize.setWidth(kPermissionColumnWidth);
+ }
+ return qsize;
+ }
+
+ if (isGroupShare()) {
+ if (row >= group_shares_.size()) {
+ return QVariant();
+ }
+ const GroupShareInfo& info = group_shares_[row];
+
+ if (column == COLUMN_NAME) {
+ return info.group.name;
+ }
+ else if (column == COLUMN_PERMISSION) {
+ if (role == Qt::DisplayRole) {
+ return info.permission == READ_WRITE ? tr("Read Write")
+ : tr("Read Only");
+ }
+ else {
+ return info.permission == READ_WRITE ? 0 : 1;
+ }
+ }
+ }
+ else {
+ if (row >= user_shares_.size()) {
+ return QVariant();
+ }
+ const UserShareInfo& info = user_shares_[row];
+
+ if (column == COLUMN_NAME) {
+ // Here the `info.user.name` field should always be non-empty:
+ // - If the share is an existing share (fetched at dialog
+ // initialization), the the user name is returned in the api
+ // request.
+ // - If the share is newly added, the user must be chosen from the
+ // completion popup, which means we have full information of the
+ // user.
+ return info.user.name;
+ }
+ else if (column == COLUMN_PERMISSION) {
+ if (role == Qt::DisplayRole) {
+ return info.permission == READ_WRITE ? tr("Read Write")
+ : tr("Read Only");
+ }
+ else {
+ return info.permission == READ_WRITE ? 0 : 1;
+ }
+ }
+ }
+
+ return QVariant();
+}
+
+void SharedItemsTableModel::onResize(const QSize& size)
+{
+ name_column_width_ = size.width() - kPermissionColumnWidth;
+ if (rowCount() != 0) {
+ emit dataChanged(index(0, COLUMN_NAME),
+ index(rowCount() - 1, COLUMN_NAME));
+ }
+}
+
+bool SharedItemsTableModel::isGroupShare() const
+{
+ return share_type_ == SHARE_TO_GROUP;
+}
+
+QVariant SharedItemsTableModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Vertical) {
+ return QVariant();
+ }
+
+ if (section == COLUMN_NAME) {
+ if (role == Qt::DisplayRole) {
+ return isGroupShare() ? tr("Group") : tr("User");
+ }
+ }
+ else if (section == COLUMN_PERMISSION) {
+ if (role == Qt::DisplayRole) {
+ return tr("Permission");
+ }
+ }
+
+
+ return QVariant();
+}
+
+
+void SharedItemsTableModel::setShareInfo(
+ const QList<GroupShareInfo>& group_shares,
+ const QList<UserShareInfo>& user_shares)
+{
+ beginResetModel();
+ group_shares_ = group_shares;
+ user_shares_ = user_shares;
+ endResetModel();
+}
+
+void SharedItemsTableModel::addNewShareInfo(UserShareInfo newinfo)
+{
+ previous_user_shares_ = user_shares_;
+ beginResetModel();
+ bool exists = false;
+ for (int i = 0; i < user_shares_.size(); i++) {
+ UserShareInfo& info = user_shares_[i];
+ if (info.user == newinfo.user) {
+ exists = true;
+ info.permission = newinfo.permission;
+ }
+ }
+ if (!exists) {
+ user_shares_.prepend(newinfo);
+ }
+ endResetModel();
+}
+
+void SharedItemsTableModel::addNewShareInfo(GroupShareInfo newinfo)
+{
+ previous_group_shares_ = group_shares_;
+ beginResetModel();
+ bool exists = false;
+ for (int i = 0; i < group_shares_.size(); i++) {
+ GroupShareInfo& info = group_shares_[i];
+ if (info.group.id == newinfo.group.id) {
+ exists = true;
+ info.permission = newinfo.permission;
+ }
+ }
+ if (!exists) {
+ group_shares_.prepend(newinfo);
+ }
+ endResetModel();
+}
+
+bool SharedItemsTableModel::shareExists(int group_id)
+{
+ foreach (const GroupShareInfo& info, group_shares_) {
+ if (info.group.id == group_id) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SharedItemsTableModel::shareExists(const SeafileUser& user)
+{
+ foreach (const UserShareInfo& info, user_shares_) {
+ if (info.user == user) {
+ return true;
+ }
+ }
+ return false;
+}
+
+GroupShareInfo SharedItemsTableModel::shareInfo(int group_id)
+{
+ foreach (const GroupShareInfo& info, group_shares_) {
+ if (info.group.id == group_id) {
+ return info;
+ }
+ }
+ return GroupShareInfo();
+}
+
+UserShareInfo SharedItemsTableModel::shareInfo(const SeafileUser& user)
+{
+ foreach (const UserShareInfo& info, user_shares_) {
+ if (info.user == user) {
+ return info;
+ }
+ }
+ return UserShareInfo();
+}
+
+Qt::ItemFlags SharedItemsTableModel::flags(const QModelIndex& index) const
+{
+ if (!index.isValid())
+ return Qt::ItemIsEnabled;
+
+ if (index.column() == COLUMN_PERMISSION) {
+ return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
+ }
+ else {
+ return QAbstractItemModel::flags(index);
+ }
+}
+
+bool SharedItemsTableModel::removeRows(int row,
+ int count,
+ const QModelIndex& parent)
+{
+ beginRemoveRows(parent, row, row);
+ if (isGroupShare()) {
+ group_shares_.removeAt(row);
+ }
+ else {
+ user_shares_.removeAt(row);
+ }
+ endRemoveRows();
+ return true;
+}
+
+bool SharedItemsTableModel::setData(const QModelIndex& index,
+ const QVariant& value,
+ int role)
+{
+ PrivateShareDialog* dialog = (PrivateShareDialog*)QObject::parent();
+ if (dialog->requestInProgress()) {
+ dialog->showWarning(tr("The previous operation is still in progres"));
+ return false;
+ }
+ if (!index.isValid() || role != Qt::EditRole) {
+ return false;
+ }
+ int permission = value.toInt();
+ int row = index.row();
+ if (isGroupShare()) {
+ previous_group_shares_ = group_shares_;
+ GroupShareInfo& info = group_shares_[row];
+ if (permission == 3) {
+ emit removeShareItem(info.group.id, info.permission);
+ removed_group_share_ = info;
+ removeRows(row, 1);
+ }
+ else if (permission == info.permission) {
+ }
+ else {
+ emit updateShareItem(info.group.id, (SharePermission)permission);
+ info.permission =
+ info.permission == READ_ONLY ? READ_WRITE : READ_ONLY;
+ emit dataChanged(index, index);
+ }
+ }
+ else {
+ previous_user_shares_ = user_shares_;
+ UserShareInfo& info = user_shares_[row];
+ if (permission == 3) {
+ emit removeShareItem(info.user, info.permission);
+ removed_user_share_ = info;
+ removeRows(row, 1);
+ }
+ else if (permission == info.permission) {
+ }
+ else {
+ emit updateShareItem(info.user, (SharePermission)permission);
+ info.permission =
+ info.permission == READ_ONLY ? READ_WRITE : READ_ONLY;
+ emit dataChanged(index, index);
+ }
+ }
+
+ return true;
+}
+
+void SharedItemsTableModel::shareOperationSuccess()
+{
+}
+
+void SharedItemsTableModel::shareOperationFailed(
+ PrivateShareRequest::ShareOperation op)
+{
+ beginResetModel();
+ if (isGroupShare()) {
+ group_shares_ = previous_group_shares_;
+ }
+ else {
+ user_shares_ = previous_user_shares_;
+ }
+ endResetModel();
+}
+
+QModelIndex SharedItemsTableModel::getIndexByGroup(int group_id) const
+{
+ for (int i = 0; i < group_shares_.size(); i++) {
+ if (group_shares_[i].group.id == group_id) {
+ return index(i, 0);
+ }
+ }
+ return index(0, 0);
+}
+
+QModelIndex SharedItemsTableModel::getIndexByUser(const SeafileUser& user) const
+{
+ for (int i = 0; i < user_shares_.size(); i++) {
+ if (user_shares_[i].user == user) {
+ return index(i, 0);
+ }
+ }
+ return index(0, 0);
+}
+
+SharedItemDelegate::SharedItemDelegate(QObject* parent)
+ : QStyledItemDelegate(parent)
+{
+}
+
+QWidget* SharedItemDelegate::createEditor(QWidget* parent,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ QComboBox* combobox = new QComboBox(parent);
+ combobox->addItem(tr("Read Write"));
+ combobox->addItem(tr("Read Only"));
+ combobox->insertSeparator(2);
+ combobox->addItem(tr("Remove Share"));
+
+ connect(combobox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(oncurrentIndexChanged()));
+
+ return combobox;
+}
+
+void SharedItemDelegate::setEditorData(QWidget* editor,
+ const QModelIndex& index) const
+{
+ int value = index.model()->data(index, Qt::EditRole).toInt();
+
+ QComboBox* combobox = static_cast<QComboBox*>(editor);
+ combobox->setCurrentIndex(value);
+}
+
+void SharedItemDelegate::setModelData(QWidget* editor,
+ QAbstractItemModel* model,
+ const QModelIndex& index) const
+{
+ QComboBox* combobox = static_cast<QComboBox*>(editor);
+ model->setData(index, combobox->currentIndex(), Qt::EditRole);
+}
+
+void SharedItemDelegate::updateEditorGeometry(
+ QWidget* editor,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ QComboBox* combobox = static_cast<QComboBox*>(editor);
+ combobox->setGeometry(option.rect);
+ // combobox->showPopup();
+}
+
+void SharedItemDelegate::paint(QPainter* painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ const SharedItemsTableModel* model =
+ static_cast<const SharedItemsTableModel*>(index.model());
+
+ QRect option_rect = option.rect;
+ bool selected = false;
+ // draw item's background
+ painter->save();
+ if (option.state & QStyle::State_Selected) {
+ painter->fillRect(option_rect, kSelectedItemBackgroundcColor);
+ selected = true;
+ }
+ else
+ painter->fillRect(option_rect, kItemBackgroundColor);
+ painter->restore();
+
+ // draw item's border for the first row only
+ static const QPen borderPen(kItemBottomBorderColor, 1);
+ // if (index.row() == 0) {
+ // painter->save();
+ // painter->setPen(borderPen);
+ // painter->drawLine(option_rect.topLeft(), option_rect.topRight());
+ // painter->restore();
+ // }
+ // draw item's border under the bottom
+ painter->save();
+ painter->setPen(borderPen);
+ painter->drawLine(option_rect.bottomLeft(), option_rect.bottomRight());
+ painter->restore();
+
+ QPoint text_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+ text_pos += option.rect.topLeft();
+
+ QSize size = model->data(index, Qt::SizeHintRole).value<QSize>();
+ QString text = model->data(index, Qt::DisplayRole).value<QString>();
+ QFont font = model->data(index, Qt::FontRole).value<QFont>();
+ QRect text_rect(text_pos, size);
+ painter->save();
+ painter->setPen(kItemColor);
+ painter->setFont(font);
+ painter->drawText(text_rect,
+ Qt::AlignLeft | Qt::AlignTop | Qt::TextSingleLine, text,
+ &text_rect);
+ painter->restore();
+
+ if (selected && index.column() == COLUMN_PERMISSION) {
+ int h = option.rect.height();
+ QPoint indicator_pos = option.rect.bottomRight() -
+ QPoint(40, h - (h - kIndicatorIconHeight) / 2);
+ indicator_pos.setX(text_rect.topRight().x() +
+ kMarginBetweenPermissionAndIndicator);
+ QRect indicator_rect(indicator_pos,
+ QSize(kIndicatorIconWidth, kIndicatorIconHeight));
+
+ QPainterPath path;
+ path.moveTo(indicator_rect.topLeft());
+ path.lineTo(indicator_rect.topRight());
+ path.lineTo(indicator_rect.bottomRight() -
+ QPoint((indicator_rect.width() / 2), 0));
+ path.lineTo(indicator_rect.topLeft());
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->setRenderHint(QPainter::HighQualityAntialiasing);
+ painter->fillPath(path, QBrush(kItemColor));
+ painter->restore();
+ }
+}
+
+void SharedItemDelegate::oncurrentIndexChanged()
+{
+ QComboBox* combobox = static_cast<QComboBox*>(sender());
+ emit commitData(combobox);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
+#define SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
+
+#include <QUrl>
+
+#include <QAbstractTableModel>
+#include <QCompleter>
+#include <QDialog>
+#include <QHash>
+#include <QScopedPointer>
+#include <QSet>
+#include <QStringList>
+#include <QStyledItemDelegate>
+#include <QTableView>
+#include <QHeaderView>
+#include "ui_private-share-dialog.h"
+
+#include "account.h"
+#include "api/contact-share-info.h"
+#include "api/requests.h"
+#include "user-name-completer.h"
+
+#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
+// only available in qt 5.0+
+#define Q_DECL_OVERRIDE
+#endif
+
+
+class QResizeEvent;
+
+class SharedItemsTableView;
+class SharedItemsTableModel;
+
+class PrivateShareDialog : public QDialog, public Ui::PrivateShareDialog
+{
+ Q_OBJECT
+public:
+ PrivateShareDialog(const Account& account,
+ const QString& repo_id,
+ const QString& repo_name,
+ const QString& path,
+ bool to_group,
+ QWidget* parent);
+
+ bool requestInProgress() const
+ {
+ return request_in_progress_;
+ }
+ void showWarning(const QString& msg);
+
+public slots:
+ void onUpdateShareItem(int group_id, SharePermission permission);
+ void onUpdateShareItem(const SeafileUser& email, SharePermission permission);
+ void onRemoveShareItem(int group_id, SharePermission permission);
+ void onRemoveShareItem(const SeafileUser& user, SharePermission permission);
+
+private slots:
+ void selectFirstRow();
+ void onNameInputEdited();
+ void onShareSuccess();
+ void onShareFailed(const ApiError& error);
+ void onUpdateShareSuccess();
+ void onUpdateShareFailed(const ApiError& error);
+ void onRemoveShareSuccess();
+ void onRemoveShareFailed(const ApiError& error);
+ void onFetchGroupsSuccess(const QList<SeafileGroup>& groups);
+ void onFetchContactsFailed(const ApiError& error);
+ void onOkBtnClicked();
+ void onGetSharedItemsSuccess(const QList<GroupShareInfo>& group_shares,
+ const QList<UserShareInfo>& user_shares);
+ void onGetSharedItemsFailed(const ApiError& error);
+ void onUserNameChoosed();
+
+private:
+ void createTable();
+ void fetchGroupsForCompletion();
+ void getExistingShardItems();
+ bool validateInputs();
+ void toggleInputs(bool enabled);
+ void enableInputs();
+ void disableInputs();
+ SharePermission currentPermission();
+ SeafileGroup findGroup(const QString& name);
+ QLineEdit* lineEdit() const
+ {
+ return to_group_ ? groupname_input_->lineEdit() : username_input_;
+ }
+ void updateUsersCompletion(const QList<SeafileUser>& users);
+
+ Account account_;
+ QString repo_id_;
+ QString repo_name_;
+ QString path_;
+ bool to_group_;
+
+ QHash<int, SeafileGroup> groups_by_id_;
+
+ // A (pattern, possible users for completion) multi map.
+ struct CachedUsersEntry {
+ QSet<SeafileUser> users;
+ qint64 ts;
+ };
+
+ SharedItemsTableView* table_;
+ SharedItemsTableModel* model_;
+
+ QScopedPointer<PrivateShareRequest, QScopedPointerDeleteLater> request_;
+ QScopedPointer<FetchGroupsRequest, QScopedPointerDeleteLater> fetch_groups_request_;
+ QScopedPointer<GetPrivateShareItemsRequest, QScopedPointerDeleteLater> get_shared_items_request_;
+ QScopedPointer<SeafileUserNameCompleter, QScopedPointerDeleteLater> user_name_completer_;
+
+ bool request_in_progress_;
+
+ QLineEdit* username_input_;
+ QComboBox* groupname_input_;
+};
+
+class SharedItemsHeadView : public QHeaderView
+{
+ Q_OBJECT
+public:
+ SharedItemsHeadView(QWidget* parent = 0);
+
+ QSize sectionSizeFromContents(int index) const Q_DECL_OVERRIDE;
+};
+
+class SharedItemsTableView : public QTableView
+{
+ Q_OBJECT
+public:
+ SharedItemsTableView(QWidget* parent = 0);
+
+ void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE;
+
+ void setModel(QAbstractItemModel* model) Q_DECL_OVERRIDE;
+
+ SharedItemsTableModel* sourceModel()
+ {
+ return source_model_;
+ }
+
+private:
+ SharedItemsTableModel* source_model_;
+};
+
+class SharedItemsTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ SharedItemsTableModel(ShareType share_type, QObject* parent = 0);
+
+ void setShareInfo(const QList<GroupShareInfo>& group_shares,
+ const QList<UserShareInfo>& user_shares);
+
+ void addNewShareInfo(UserShareInfo info);
+ void addNewShareInfo(GroupShareInfo info);
+
+ bool shareExists(int group_id);
+ bool shareExists(const SeafileUser& user);
+
+ GroupShareInfo shareInfo(int group_id);
+ UserShareInfo shareInfo(const SeafileUser& user);
+
+ void shareOperationSuccess();
+ void shareOperationFailed(PrivateShareRequest::ShareOperation op);
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const
+ Q_DECL_OVERRIDE;
+ int columnCount(const QModelIndex& parent = QModelIndex()) const
+ Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex& index,
+ int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE;
+ bool setData(const QModelIndex& index,
+ const QVariant& value,
+ int role) Q_DECL_OVERRIDE;
+ bool removeRows(int row,
+ int count,
+ const QModelIndex& parent = QModelIndex()) Q_DECL_OVERRIDE;
+
+ QVariant headerData(int section,
+ Qt::Orientation orientation,
+ int role) const Q_DECL_OVERRIDE;
+
+ int nameColumnWidth() const
+ {
+ return name_column_width_;
+ }
+
+ QModelIndex getIndexByGroup(int group_id) const;
+ QModelIndex getIndexByUser(const SeafileUser& user) const;
+signals:
+ void updateShareItem(int group_id, SharePermission permission);
+ void updateShareItem(const SeafileUser& user, SharePermission permission);
+ void removeShareItem(int group_id, SharePermission permission);
+ void removeShareItem(const SeafileUser& user, SharePermission permission);
+
+public slots:
+ void onResize(const QSize& size);
+
+private:
+ bool isGroupShare() const;
+
+ QList<UserShareInfo> user_shares_, previous_user_shares_;
+ QList<GroupShareInfo> group_shares_, previous_group_shares_;
+
+ ShareType share_type_;
+ int name_column_width_;
+
+ GroupShareInfo removed_group_share_;
+ UserShareInfo removed_user_share_;
+};
+
+
+class SharedItemDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ SharedItemDelegate(QObject* parent = 0);
+
+ QWidget* createEditor(QWidget* parent,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+ void setEditorData(QWidget* editor,
+ const QModelIndex& index) const Q_DECL_OVERRIDE;
+ void setModelData(QWidget* editor,
+ QAbstractItemModel* model,
+ const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+ void updateEditorGeometry(QWidget* editor,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+ void paint(QPainter* painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const Q_DECL_OVERRIDE;
+
+private slots:
+ void oncurrentIndexChanged();
+};
+
+
+#endif // SEAFILE_CLIENT_UI_PRIVATE_SHARE_DIALOG_H
--- /dev/null
+#include <cstdio>
+#include <QStyleOptionTab>
+
+#include "proxy-style.h"
+
+void SeafileProxyStyle::drawControl(ControlElement element,
+ const QStyleOption * option,
+ QPainter * painter,
+ const QWidget * widget) const
+{
+
+ if (element == CE_TabBarTabLabel) {
+ // printf ("[draw tab label] name is %s\n", widget->objectName().toUtf8().data());
+ if (const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(option)) {
+ if (tb->state & State_HasFocus) {
+ QStyleOptionTab t(*tb);
+ t.state = t.state ^ State_HasFocus;
+ QProxyStyle::drawControl(element, &t, painter, widget);
+ return;
+ }
+ }
+ }
+
+ if (element == CE_TabBarTab) {
+ // printf ("[draw tab] name is %s\n", widget->objectName().toUtf8().data());
+ }
+
+ QProxyStyle::drawControl(element, option, painter, widget);
+}
--- /dev/null
+#ifndef SEAFILE_CLEINT_PROXY_STYLE
+#define SEAFILE_CLEINT_PROXY_STYLE
+
+#include <QProxyStyle>
+
+class QStyleOption;
+class QPainter;
+class QWidget;
+
+/**
+ * Use a custom proxy style to remove the border of tabbar text when selected
+ * See http://stackoverflow.com/questions/7492080/styling-the-text-outline-in-qts-tabs
+ */
+class SeafileProxyStyle: public QProxyStyle {
+public:
+ virtual void drawControl (ControlElement element, const QStyleOption * option,
+ QPainter * painter, const QWidget * widget = 0) const;
+};
+
+#endif // SEAFILE_CLEINT_PROXY_STYLE
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QDir>
+#include <QTimer>
+
+#include "utils/utils.h"
+#include "account-mgr.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "api/requests.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "rpc/local-repo.h"
+#include "utils/utils.h"
+
+#include "repo-detail-dialog.h"
+
+namespace {
+
+
+const int kRefrshRepoStatusInterval = 1000; // 1s
+
+} // namespace
+
+
+RepoDetailDialog::RepoDetailDialog(const ServerRepo &repo, QWidget *parent)
+ : QDialog(parent),
+ repo_(repo)
+{
+ setupUi(this);
+ setWindowTitle(tr("Library \"%1\"").arg(repo.name));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ mTimeLabel->setText(translateCommitTime(repo.mtime));
+ mOwnerLabel->setText(repo.owner);
+ mSizeLabel->setText(readableFileSize(repo.size));
+
+ LocalRepo lrepo;
+ seafApplet->rpcClient()->getLocalRepo(repo.id, &lrepo);
+ if (lrepo.isValid()) {
+ lpathLabel->setVisible(true);
+ mLpathLabel->setVisible(true);
+ mLpathLabel->setText(QDir::toNativeSeparators(lrepo.worktree));
+ if (lrepo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+ mStatus->setText(lrepo.sync_error_str);
+ } else {
+ mStatus->setText(lrepo.sync_state_str);
+ }
+ } else {
+ mStatus->setText(tr("This library is not downloaded yet"));
+ lpathLabel->setVisible(false);
+ mLpathLabel->setVisible(false);
+ }
+
+ mRepoIcon->setPixmap(repo_.getPixmap());
+ mRepoName->setText(repo_.name);
+ #if defined(Q_OS_MAC)
+ layout()->setContentsMargins(8, 9, 9, 4);
+ layout()->setSpacing(5);
+ #endif
+
+ resize(sizeHint());
+ updateRepoStatus();
+
+ refresh_timer_ = new QTimer(this);
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(updateRepoStatus()));
+ refresh_timer_->start(kRefrshRepoStatusInterval);
+}
+
+void RepoDetailDialog::updateRepoStatus()
+{
+ LocalRepo r;
+ QString text;
+ seafApplet->rpcClient()->getLocalRepo(repo_.id, &r);
+ if (r.isValid()) {
+ if (r.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+ text = "<p style='color:red'>" + tr("Error: ") + r.sync_error_str + "</p>";
+ } else {
+ text = r.sync_state_str;
+ if (r.sync_state == LocalRepo::SYNC_STATE_ING) {
+ // add transfer rate and finished percent
+ int rate, percent;
+ if (seafApplet->rpcClient()->getRepoTransferInfo(repo_.id, &rate, &percent) == 0) {
+ text += ", " + QString::number(percent) + "%, " + QString("%1 kB/s").arg(rate / 1024);
+ }
+ }
+ }
+
+ int sync_interval = 0;
+ QString interval_string;
+ if (seafApplet->rpcClient()->getRepoProperty(r.id, "sync-interval", &interval_string) == 0) {
+ sync_interval = interval_string.toInt();
+ if (sync_interval > 0) {
+ mSyncInterval->setText(tr("every %1 seconds").arg(sync_interval));
+ } else {
+ mSyncIntervalLabel->hide();
+ mSyncInterval->hide();
+ }
+ }
+
+ } else {
+ std::vector<CloneTask> tasks;
+ seafApplet->rpcClient()->getCloneTasks(&tasks);
+
+ CloneTask task;
+
+ if (!tasks.empty()) {
+ for (size_t i = 0; i < tasks.size(); ++i) {
+ CloneTask clone_task = tasks[i];
+ if (clone_task.repo_id == repo_.id) {
+ task = clone_task;
+ break;
+ }
+ }
+ }
+
+ if (task.isValid() && task.isDisplayable()) {
+ if (task.error_str.length() > 0) {
+ text = task.error_str;
+ } else {
+ text = task.state_str;
+ }
+ } else {
+ text = tr("This library is not downloaded yet");
+ }
+
+ mSyncIntervalLabel->hide();
+ mSyncInterval->hide();
+ }
+
+ mStatus->setText(text);
+}
--- /dev/null
+#include <QDialog>
+#include <QUrl>
+#include <QString>
+
+#include "ui_repo-detail-dialog.h"
+#include "api/server-repo.h"
+#include "rpc/local-repo.h"
+
+class QTimer;
+
+class RepoDetailDialog : public QDialog,
+ public Ui::RepoDetailDialog
+{
+ Q_OBJECT
+public:
+ RepoDetailDialog(const ServerRepo &repo, QWidget *parent=0);
+
+private slots:
+ void updateRepoStatus();
+
+private:
+ Q_DISABLE_COPY(RepoDetailDialog);
+
+ ServerRepo repo_;
+ QTimer *refresh_timer_;
+};
--- /dev/null
+#include <QPainter>
+#include <QApplication>
+#include <QPixmap>
+#include <QToolTip>
+#include <QSortFilterProxyModel>
+
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "seafile-applet.h"
+#include "settings-mgr.h"
+#include "api/server-repo.h"
+#include "repo-item.h"
+#include "repo-tree-view.h"
+#include "repo-tree-model.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "QtAwesome.h"
+
+#include "repo-item-delegate.h"
+
+namespace {
+
+/**
+ RepoName
+ RepoIcon statusIcon
+ subtitle
+ */
+
+const int kMarginLeft = 16;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 2;
+const int kRepoItemVerticalMargin = 13;
+const int kRepoCategoryVerticalMargin = 10;
+
+const int kRepoIconHeight = 36;
+const int kRepoIconWidth = 36;
+const int kRepoIconHeightAlpha = 24;
+const int kRepoIconWidthAlpha = 24;
+const int kRepoNameWidth = 175;
+const int kRepoNameHeight = 30;
+const int kRepoNameHeightAlpha = 20;
+const int kRepoDescriptionHeightAlpha = 14;
+const int kRepoStatusIconWidth = 24;
+const int kRepoStatusIconHeight = 24;
+const int kRepoStatusIconWidthAlpha = 16;
+const int kRepoStatusIconHeightAlpha = 16;
+
+const char *kRepoCategoryIndicatorColor = "#BBB";
+const int kRepoCategoryNameMaxWidth = 400;
+const int kRepoCategoryIndicatorWidth = 20;
+const int kRepoCategoryIndicatorHeight = 20;
+const int kMarginBetweenIndicatorAndName = 5;
+
+const int kMarginBetweenRepoIconAndName = 10;
+const int kMarginBetweenRepoNameAndStatus = 20;
+
+const char *kRepoNameColor = "#141414";
+const char *kRepoNameColorHighlighted = "#544D49";
+const char *kTimestampColor = "#AAAAAA";
+const char *kTimestampColorHighlighted = "#9D9B9A";
+const int kRepoNameFontSize = 14;
+const int kTimestampFontSize = 12;
+const int kRepoDescriptionFontSizeAlpha = 10;
+const int kRepoCategoryNameFontSize = 14;
+const int kRepoCategoryCountFontSize = 12;
+const int kRepoCategoryCountFontSizeAlpha = 14;
+const int kOwnerFontSize = 12;
+const int kOwnerFontSizeAlpha = 10;
+
+const char *kRepoItemBackgroundColorHighlightedAlpha = "#EFEEEE";
+const char *kRepoItemBackgroundColor = "white";
+const char *kRepoItemBackgroundColorDragMove = "#EFEEEE";
+
+const char *kRepoCategoryColor = "#747474";
+
+const char *kRepoCategoryBackgroundColor = "white";
+
+const int kRepoCategoryCountMarginRight = 10;
+const int kRepoCategoryCountMarginRightAlpha = 20;
+const char *kRepoCategoryCountColor = "#AAAAAA";
+
+static void showTooltip(const QString &text,
+ QWidget *viewport,
+ const QRect &rect,
+ const QRect &small_rect)
+{
+ QPoint tool_tip_pos =
+ viewport->mapToGlobal(small_rect.center() + rect.topLeft());
+ QToolTip::showText(
+ tool_tip_pos, text, viewport, small_rect.translated(rect.topLeft()));
+}
+
+} // namespace
+
+RepoItemDelegate::RepoItemDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+}
+
+QSize RepoItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ QStandardItem *item = getItem(index);
+ if (!item) {
+ return QStyledItemDelegate::sizeHint(option, index);
+ }
+
+ if (item->type() == REPO_ITEM_TYPE) {
+ return sizeHintForRepoItem(option, (const RepoItem *)item);
+ } else {
+ // return QStyledItemDelegate::sizeHint(option, index);
+ return sizeHintForRepoCategoryItem(option, (const RepoCategoryItem *)item);
+ }
+}
+
+QSize RepoItemDelegate::sizeHintForRepoItem(const QStyleOptionViewItem &option,
+ const RepoItem *item) const
+{
+
+ int width = kMarginLeft + kRepoIconWidthAlpha
+ + kMarginBetweenRepoIconAndName + kRepoNameWidth
+ + kMarginBetweenRepoNameAndStatus + kRepoStatusIconWidthAlpha
+ + kMarginRight + kPadding * 2;
+
+ // int height = kRepoIconHeightAlpha + kPadding * 2 + kMarginTop + kMarginBottom;
+ int height = kRepoIconHeightAlpha + kRepoItemVerticalMargin * 2;
+
+ // qDebug("width = %d, height = %d\n", width, height);
+
+ return QSize(width, height);
+}
+
+QSize RepoItemDelegate::sizeHintForRepoCategoryItem(const QStyleOptionViewItem &option,
+ const RepoCategoryItem *item) const
+{
+ int width, height;
+
+ QFontMetrics qfm(changeFontSize(option.font, kRepoCategoryNameFontSize));
+ QSize size = qfm.size(0, item->name());
+
+ width = qMin(size.width(), kRepoCategoryIndicatorWidth)
+ + kMarginBetweenIndicatorAndName + kRepoCategoryNameMaxWidth;
+
+ // height = qMax(size.height(), kRepoCategoryIndicatorHeight) + kPadding;
+ height = qMax(size.height(), kRepoCategoryIndicatorHeight) + kRepoCategoryVerticalMargin * 2;
+
+ RepoTreeModel *model = (RepoTreeModel *)item->model();
+ model->repo_category_height = height;
+
+ // qDebug("width = %d, height = %d\n", width, height);
+
+ return QSize(width, height);
+}
+
+
+void RepoItemDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ QStandardItem *item = getItem(index);
+ if (!item) {
+ QStyledItemDelegate::paint(painter, option, index);
+ return;
+ }
+
+ if (item->type() == REPO_ITEM_TYPE) {
+ paintRepoItem(painter, option, (RepoItem *)item);
+ } else {
+ paintRepoCategoryItem(painter, option, (RepoCategoryItem *)item);
+ }
+
+ // fix for showing first category if hidden
+ RepoTreeView *view = static_cast<RepoTreeView*>(parent());
+ QModelIndex top_index = view->indexAt(QPoint(0, 0)).parent();
+ if (top_index.isValid()) {
+ if (option.rect.contains(QPoint(0, 0))) {
+ const RepoCategoryItem *category_item =
+ static_cast<RepoCategoryItem *>(getItem(top_index));
+ QStyleOptionViewItem category_option = option;
+ category_option.rect = QRect(0, 0, option.rect.width(),
+ sizeHintForRepoCategoryItem(option, category_item).height());
+ paintRepoCategoryItem(painter, category_option, category_item);
+ }
+ }
+}
+
+void RepoItemDelegate::paintRepoItem(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const RepoItem *item) const
+{
+ const ServerRepo& repo = item->repo();
+ QBrush backBrush;
+ bool selected = false;
+
+ RepoTreeModel *model = (RepoTreeModel *)item->model();
+ RepoTreeView *view = model->treeView();
+ QModelIndex index = ((QSortFilterProxyModel *)view->model())->mapFromSource(model->indexFromItem(item));
+ if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+ backBrush = QColor(kRepoItemBackgroundColorHighlightedAlpha);
+ selected = true;
+ } else if (view->getCurrentDropTarget() == index) {
+ backBrush = QColor(kRepoItemBackgroundColorDragMove);
+ } else {
+ backBrush = QColor(kRepoItemBackgroundColor);
+ }
+
+ painter->save();
+ painter->fillRect(option.rect, backBrush);
+ painter->restore();
+
+ int indent_left = 0;
+ if (item->level() > 0) {
+ indent_left = kRepoCategoryIndicatorWidth + kMarginBetweenIndicatorAndName;
+ }
+
+ // Paint repo icon
+ QPoint repo_icon_pos(kMarginLeft + kPadding + indent_left, kRepoItemVerticalMargin);
+ repo_icon_pos += option.rect.topLeft();
+
+ // get the device pixel radio from current painter device
+ int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ scale_factor = painter->device()->devicePixelRatio();
+#endif // QT5
+ QPixmap repo_icon = repo.getIcon().pixmap(QSize(kRepoIconWidthAlpha, kRepoIconHeightAlpha));
+
+ QRect repo_icon_rect(repo_icon_pos, QSize(kRepoIconWidthAlpha, kRepoIconHeightAlpha));
+ painter->save();
+ painter->drawPixmap(repo_icon_rect, repo_icon);
+ painter->restore();
+
+ // Paint repo name
+ int vertical_margin_between_icon_and_name = 0;
+#ifdef Q_OS_WIN32
+ vertical_margin_between_icon_and_name = -9;
+#else
+ vertical_margin_between_icon_and_name = -5;
+#endif
+ QPoint repo_name_pos = repo_icon_pos + QPoint(kRepoIconWidthAlpha + kMarginBetweenRepoIconAndName,
+ vertical_margin_between_icon_and_name);
+ int repo_name_width = option.rect.width() - kRepoIconWidthAlpha - kMarginBetweenRepoIconAndName
+ - kRepoStatusIconWidthAlpha - kMarginBetweenRepoNameAndStatus
+ - kPadding * 2 - kMarginLeft - kMarginRight;
+ repo_name_width -= indent_left;
+ int repo_name_height = ::textHeightInFont(repo.name, changeFontSize(painter->font(), kRepoNameFontSize));
+ QRect repo_name_rect(repo_name_pos, QSize(repo_name_width, repo_name_height));
+ painter->save();
+ painter->setPen(QColor(selected ? kRepoNameColorHighlighted : kRepoNameColor));
+ painter->setFont(changeFontSize(painter->font(), kRepoNameFontSize));
+ painter->drawText(repo_name_rect,
+ Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+ fitTextToWidth(repo.name, painter->font(), repo_name_width),
+ &repo_name_rect);
+ painter->restore();
+
+ // Paint repo description
+ QString description;
+ const LocalRepo& r = item->localRepo();
+ if (r.isValid()) {
+ if (r.sync_state == LocalRepo::SYNC_STATE_ING) {
+ description = r.sync_state_str;
+ if (r.has_data_transfer) {
+ int rate, percent;
+ if (seafApplet->rpcClient()->getRepoTransferInfo(r.id, &rate, &percent) == 0) {
+ description += ", " + QString::number(percent) + "%";
+ }
+ }
+ } else if (r.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+ description = r.getErrorString();
+ }
+ } else {
+ const CloneTask& task = item->cloneTask();
+ if (task.isValid() && task.isDisplayable()) {
+ if (task.error_str.length() > 0) {
+ description = task.error_str;
+ } else {
+ description = task.state_str;
+ }
+ }
+ }
+
+ if (description.isEmpty()) {
+ description = translateCommitTime(repo.mtime);
+ }
+ painter->save();
+ QPoint repo_desc_pos = repo_name_rect.bottomLeft() + QPoint(0, 5);
+ int repo_desc_height = ::textHeightInFont(description, changeFontSize(painter->font(), kRepoDescriptionFontSizeAlpha));
+ QRect repo_desc_rect(repo_desc_pos, QSize(repo_name_width, repo_desc_height));
+ painter->setFont(changeFontSize(painter->font(), kRepoDescriptionFontSizeAlpha));
+ painter->setPen(QColor(selected ? kTimestampColorHighlighted : kTimestampColor));
+ painter->drawText(repo_desc_rect,
+ Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+ fitTextToWidth(description, painter->font(), repo_name_width),
+ &repo_desc_rect);
+ painter->restore();
+
+ // Paint extra description
+ QString extra_description;
+ if (repo.isSubfolder()) {
+ ServerRepo parent_repo = RepoService::instance()->getRepo(repo.parent_repo_id);
+ extra_description = tr(", %1%2").arg(parent_repo.name).arg(repo.parent_path);
+ }
+ // Paint repo sharing owner for private share
+ if (static_cast<RepoCategoryItem*>(item->parent())->categoryIndex() ==
+ RepoTreeModel::CAT_INDEX_SHARED_REPOS)
+ extra_description += tr(", %1").arg(repo.owner.split('@').front());
+ if (!extra_description.isEmpty()) {
+ int width = option.rect.topRight().x() - 40 - repo_desc_rect.topRight().x();
+ if (width < 3)
+ width = 3;
+ int vertical_margin_between_desc_and_extra_desc = 0;
+#ifdef Q_OS_LINUX
+ vertical_margin_between_desc_and_extra_desc = 3;
+#endif
+ QPoint repo_owner_pos = repo_desc_rect.topRight() + QPoint(0, vertical_margin_between_desc_and_extra_desc);
+ int extra_desc_height = ::textHeightInFont(extra_description, changeFontSize(painter->font(), kOwnerFontSizeAlpha));
+ QRect repo_owner_rect(repo_owner_pos, QSize(width, extra_desc_height));
+
+ painter->save();
+ painter->setFont(changeFontSize(painter->font(), kOwnerFontSizeAlpha));
+ painter->setPen(QColor(selected ? kTimestampColorHighlighted : kTimestampColor));
+ painter->drawText(repo_owner_rect,
+ Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+ fitTextToWidth(extra_description, painter->font(), width),
+ &repo_owner_rect);
+
+ painter->restore();
+ }
+
+ // Paint repo status icon
+ QPoint status_icon_pos = option.rect.topRight() - QPoint(41, 0);
+ status_icon_pos.setY(option.rect.center().y() - (kRepoStatusIconHeightAlpha / 2));
+ QRect status_icon_rect(status_icon_pos, QSize(kRepoStatusIconWidthAlpha, kRepoStatusIconHeightAlpha));
+
+ QPixmap status_icon_pixmap = getSyncStatusIcon(item).pixmap(status_icon_rect.size());
+
+ painter->save();
+ painter->drawPixmap(status_icon_rect, status_icon_pixmap);
+ painter->restore();
+
+ // Update the metrics of this item
+ RepoItem::Metrics metrics;
+ QPoint shift(-option.rect.topLeft().x(), -option.rect.topLeft().y());
+ metrics.icon_rect = repo_icon_rect;
+ metrics.name_rect = repo_name_rect;
+ metrics.subtitle_rect = repo_desc_rect;
+ metrics.status_icon_rect = status_icon_rect;
+
+ metrics.icon_rect.translate(shift);
+ metrics.name_rect.translate(shift);
+ metrics.subtitle_rect.translate(shift);
+ metrics.status_icon_rect.translate(shift);
+
+ item->setMetrics(metrics);
+}
+
+void RepoItemDelegate::paintRepoCategoryItem(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const RepoCategoryItem *item) const
+{
+ QBrush backBrush = QColor(kRepoCategoryBackgroundColor);
+
+ painter->save();
+ painter->fillRect(option.rect, backBrush);
+ painter->restore();
+
+ // Paint the expand/collapse indicator
+ painter->save();
+
+ RepoTreeModel *model = (RepoTreeModel *)item->model();
+ RepoTreeView *view = model->treeView();
+ QModelIndex index = ((QSortFilterProxyModel *)view->model())->mapFromSource(model->indexFromItem(item));
+ bool expanded = view->isExpanded(index);
+ int indent_left = 0;
+ if (item->level() > 0) {
+ indent_left = kRepoCategoryIndicatorWidth + kMarginBetweenIndicatorAndName;
+ }
+
+ int repo_category_text_height = ::textHeightInFont(item->name(), changeFontSize(option.font, kRepoCategoryNameFontSize));
+ int vertical_padding_between_indicator_and_name = (repo_category_text_height - kRepoCategoryIndicatorHeight) / 2;
+
+ // [(size of category icon) - (size of repo icon)] / 2
+ int indicator_offset = (24 - 20) / 2;
+ QRect indicator_rect(option.rect.topLeft() +
+ QPoint(kPadding + indicator_offset + kMarginLeft + indent_left,
+ kRepoCategoryVerticalMargin + vertical_padding_between_indicator_and_name),
+ QSize(kRepoCategoryIndicatorWidth, kRepoCategoryIndicatorHeight));
+ // get the device pixel radio from current painter device
+ int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ scale_factor = painter->device()->devicePixelRatio();
+#endif // QT5
+
+ QIcon icon(expanded ? awesome->icon(icon_caret_down, kRepoCategoryIndicatorColor)
+ : awesome->icon(icon_caret_right, kRepoCategoryIndicatorColor));
+ QPixmap icon_pixmap(icon.pixmap(QSize(kRepoCategoryIndicatorWidth, kRepoCategoryIndicatorWidth)));
+ painter->drawPixmap(indicator_rect, icon_pixmap);
+ painter->restore();
+
+ // Paint category name
+
+ // calculate the count of synced repos
+ int synced_repos = 0;
+ for (int i = 0; i < item->rowCount(); ++i) {
+ QStandardItem *child = item->child(i);
+ if (child->type() == REPO_ITEM_TYPE) {
+ RepoItem *repo_item = static_cast<RepoItem *>(child);
+ if (repo_item->localRepo().isValid())
+ ++synced_repos;
+ } else {
+ RepoCategoryItem *cat_item = static_cast<RepoCategoryItem *>(child);
+ for (int j = 0; j < cat_item->rowCount(); ++j) {
+ RepoItem *repo_item = static_cast<RepoItem *>(cat_item->child(j));
+ if (repo_item->localRepo().isValid())
+ ++synced_repos;
+ }
+ }
+ }
+ const QString category_count_text = QString::number(synced_repos) + "/" + QString::number(item->matchedReposCount());
+ const int category_count_width = ::textWidthInFont(category_count_text, changeFontSize(option.font, kRepoCategoryCountFontSizeAlpha));
+
+ painter->save();
+
+ int right_shift = kMarginLeft + kRepoIconWidthAlpha + kMarginBetweenRepoIconAndName - kRepoCategoryIndicatorWidth - kMarginLeft;
+ QPoint category_name_pos = indicator_rect.topRight() +
+ QPoint(right_shift - 1, - vertical_padding_between_indicator_and_name);
+ QRect category_name_rect(category_name_pos,
+ option.rect.bottomRight() - QPoint(kPadding + category_count_width + kRepoCategoryCountMarginRightAlpha,
+ kRepoCategoryVerticalMargin));
+ painter->setPen(QColor(kRepoCategoryColor));
+ painter->setFont(changeFontSize(option.font, kRepoCategoryNameFontSize));
+ painter->drawText(category_name_rect,
+ Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
+ fitTextToWidth(item->name(), painter->font(), category_name_rect.width()));
+ painter->restore();
+
+ // Paint category count
+ painter->save();
+ QPoint category_count_pos = option.rect.topRight() +
+ QPoint(-category_count_width - kRepoCategoryCountMarginRightAlpha, 0);
+ category_count_pos.setY(category_name_pos.y());
+ QRect category_count_rect(category_count_pos,
+ option.rect.bottomRight() - QPoint(kRepoCategoryCountMarginRightAlpha, kRepoCategoryVerticalMargin));
+ painter->setFont(changeFontSize(option.font, kRepoCategoryCountFontSizeAlpha));
+ painter->setPen(QColor(kRepoCategoryCountColor));
+ painter->drawText(category_count_rect,
+ Qt::AlignLeft | Qt::AlignTop,
+ category_count_text);
+ painter->restore();
+}
+
+QIcon RepoItemDelegate::getSyncStatusIcon(const RepoItem *item) const
+{
+ const QString prefix = ":/images/sync/";
+ const LocalRepo& repo = item->localRepo();
+ QString icon;
+ if (!repo.isValid()) {
+ icon = "cloud-unsynced";
+ } else if (!seafApplet->settingsManager()->autoSync()) {
+ icon = "pause";
+ } else {
+ switch (repo.sync_state) {
+ case LocalRepo::SYNC_STATE_DONE:
+ icon = "cloud-synced";
+ break;
+ case LocalRepo::SYNC_STATE_ING:
+ icon = "cloud-sync";
+ break;
+ case LocalRepo::SYNC_STATE_ERROR:
+ icon = "exclamation";
+ break;
+ case LocalRepo::SYNC_STATE_WAITING:
+ icon = "waiting";
+ break;
+ case LocalRepo::SYNC_STATE_DISABLED:
+ icon = "pause";
+ break;
+ case LocalRepo::SYNC_STATE_UNKNOWN:
+ icon = "question";
+ break;
+ case LocalRepo::SYNC_STATE_INIT:
+ // If the repo is in "sync init", we just display the previous
+ // icon.
+ icon = last_icon_map_.value(repo.id, "waiting");
+ break;
+ }
+ }
+
+ last_icon_map_[repo.id] = icon;
+
+ return QIcon(prefix + icon + ".png");
+}
+
+QStandardItem* RepoItemDelegate::getItem(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return NULL;
+ }
+ QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)index.model();
+ RepoTreeModel *tree_model_ = (RepoTreeModel *)(proxy->sourceModel());
+ QStandardItem *item = tree_model_->itemFromIndex(proxy->mapToSource(index));
+ if (item->type() != REPO_ITEM_TYPE &&
+ item->type() != REPO_CATEGORY_TYPE) {
+ return NULL;
+ }
+ return item;
+}
+
+void RepoItemDelegate::showRepoItemToolTip(const RepoItem *item,
+ const QPoint& global_pos,
+ QWidget *viewport,
+ const QRect& rect) const
+{
+ const RepoItem::Metrics& metrics = item->metrics();
+
+ const QRect& status_icon_rect = metrics.status_icon_rect;
+ const QRect& subtitle_rect = metrics.subtitle_rect;
+
+ QPoint viewpos = viewport->mapFromGlobal(global_pos);
+ viewpos -= rect.topLeft();
+
+ if (status_icon_rect.contains(viewpos)) {
+ QString text = "<p style='white-space:pre'>";
+ const LocalRepo& local_repo = item->localRepo();
+ if (!local_repo.isValid()) {
+ text += tr("This library has not been downloaded");
+ } else {
+ if (local_repo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+ text += local_repo.getErrorString();
+ } else {
+ text += local_repo.sync_state_str;
+ }
+ }
+ text += "</p>";
+
+ showTooltip(text, viewport, rect, status_icon_rect);
+
+ } else if (subtitle_rect.contains(viewpos)) {
+ QString text = "<p style='white-space:pre'>";
+ const LocalRepo& local_repo = item->localRepo();
+ if (local_repo.isValid() && local_repo.sync_state == LocalRepo::SYNC_STATE_ERROR) {
+ text += local_repo.getErrorString();
+ text += "</p>";
+ showTooltip(text, viewport, rect, subtitle_rect);
+ }
+ }
+}
+
--- /dev/null
+#ifndef SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+#define SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+
+#include <QStyledItemDelegate>
+#include <QHash>
+
+class QStandardItem;
+class QModelIndex;
+class QWidget;
+
+class ServerRepo;
+class RepoItem;
+class RepoCategoryItem;
+
+class RepoItemDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+public:
+ explicit RepoItemDelegate(QObject *parent=0);
+
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+ void showRepoItemToolTip(const RepoItem *item,
+ const QPoint& global_pos,
+ QWidget *viewport,
+ const QRect& rect) const;
+
+private:
+ QStandardItem* getItem(const QModelIndex &index) const;
+ void paintRepoItem(QPainter *painter,
+ const QStyleOptionViewItem& opt,
+ const RepoItem *item) const;
+
+ void paintRepoCategoryItem(QPainter *painter,
+ const QStyleOptionViewItem& opt,
+ const RepoCategoryItem *item) const;
+
+ QSize sizeHintForRepoCategoryItem(const QStyleOptionViewItem &option,
+ const RepoCategoryItem *item) const;
+
+ QSize sizeHintForRepoItem(const QStyleOptionViewItem &option,
+ const RepoItem *item) const;
+
+ QIcon getSyncStatusIcon(const RepoItem *item) const;
+
+ mutable QHash<QString, QString> last_icon_map_;
+};
+
+
+#endif // SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
--- /dev/null
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "repo-item.h"
+
+RepoItem::RepoItem(const ServerRepo& repo)
+ : SeafileRepoBaseItem(),
+ repo_(repo)
+{
+ setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ LocalRepo local_repo;
+ seafApplet->rpcClient()->getLocalRepo(repo.id, &local_repo);
+ setLocalRepo(local_repo);
+
+ sync_now_clicked_ = false;
+}
+
+void RepoItem::setRepo(const ServerRepo& repo)
+{
+ repo_ = repo;
+}
+
+void RepoItem::setLocalRepo(const LocalRepo& repo)
+{
+ local_repo_ = repo;
+}
+
+bool RepoItem::repoDownloadable() const
+{
+ if (local_repo_.isValid()) {
+ return false;
+ }
+
+ if (!clone_task_.isValid()) {
+ return true;
+ }
+
+ QString state = clone_task_.state;
+ if (state == "canceled" || state == "error" || state == "done") {
+ return true;
+ }
+
+ return false;
+}
+
+QVariant RepoItem::data(int role) const
+{
+ if (role == Qt::DisplayRole) {
+ return repo_.name;
+ } else {
+ return QVariant();
+ }
+}
+
+RepoCategoryItem::RepoCategoryItem(int cat_index, const QString& name, int group_id)
+ : SeafileRepoBaseItem(),
+ cat_index_(cat_index),
+ name_(name),
+ group_id_(group_id),
+ matched_repos_(-1)
+{
+ setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+}
+
+QVariant RepoCategoryItem::data(int role) const
+{
+ if (role != Qt::DisplayRole) {
+ return QVariant();
+ }
+
+ return name_;
+}
+
+int RepoCategoryItem::matchedReposCount() const
+{
+ if (isGroupsRoot()) {
+ // This item is the groups root level.
+ int i, n = rowCount(), sum = 0;
+ for (i = 0; i < n; i++) {
+ RepoCategoryItem *group = (RepoCategoryItem *)child(i);
+ sum += group->matchedReposCount();
+ }
+ return sum;
+ }
+
+ // A normal group item.
+ return matched_repos_ >= 0 ? matched_repos_ : rowCount();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_REPO_ITEM_H
+#define SEAFILE_CLIENT_REPO_ITEM_H
+
+#include <QStandardItem>
+#include "api/server-repo.h"
+#include "rpc/local-repo.h"
+#include "rpc/clone-task.h"
+
+#define MY_REPOS "My Libraries"
+#define SHARED_REPOS "Shared Libraries"
+
+enum {
+ REPO_ITEM_TYPE = QStandardItem::UserType,
+ REPO_CATEGORY_TYPE
+};
+
+
+class SeafileRepoBaseItem : public QStandardItem
+{
+public:
+ SeafileRepoBaseItem() : level_(0){};
+
+ void setLevel(int level)
+ {
+ level_ = level;
+ }
+
+ int level() const
+ {
+ return level_;
+ }
+
+private:
+ int level_;
+};
+
+
+/**
+ * Represent a repo
+ */
+class RepoItem : public SeafileRepoBaseItem {
+public:
+ RepoItem(const ServerRepo& repo);
+
+ void setRepo(const ServerRepo& repo);
+ void setLocalRepo(const LocalRepo& repo);
+
+ virtual int type() const { return REPO_ITEM_TYPE; }
+
+ const ServerRepo& repo() const { return repo_; }
+ const LocalRepo& localRepo() const { return local_repo_; }
+
+ /**
+ * Although we don't use this in our custom delegate, we need to
+ * implemented it for our proxy filter model.
+ */
+ QVariant data(int role=Qt::UserRole + 1) const;
+
+ /**
+ * Every time the item is painted, we record the metrics of each part of
+ * the item on the screen. So later we the mouse click/hover the item, we
+ * can decide which part is hovered, and to do corresponding actions.
+ */
+ struct Metrics {
+ QRect icon_rect;
+ QRect name_rect;
+ QRect subtitle_rect;
+ QRect status_icon_rect;
+ };
+
+ void setMetrics(const Metrics& metrics) const { metrics_ = metrics; }
+ const Metrics& metrics() const { return metrics_; }
+
+ void setCloneTask(const CloneTask& task=CloneTask()) { clone_task_ = task; }
+ const CloneTask& cloneTask() const { return clone_task_; }
+
+ bool repoDownloadable() const;
+
+ void setSyncNowClicked(bool val) { sync_now_clicked_ = val; }
+ bool syncNowClicked() const { return sync_now_clicked_; }
+
+private:
+ ServerRepo repo_;
+ LocalRepo local_repo_;
+
+ mutable Metrics metrics_;
+ CloneTask clone_task_;
+
+ bool sync_now_clicked_;
+};
+
+/**
+ * Represent a repo category
+ * E.g (My Repos, Shared repos, Group 1 repos, Group 2 repos ...)
+ */
+class RepoCategoryItem: public SeafileRepoBaseItem {
+public:
+ /**
+ * Create a group category
+ * @group_id: -1 for non groups categories
+ * 0 for the groups root item
+ * > 0 for group items
+ */
+ RepoCategoryItem(int cat_index, const QString& name, int group_id=-1);
+
+ virtual int type() const { return REPO_CATEGORY_TYPE; }
+
+ // Accessors
+ const QString& name() const { return name_; }
+
+ bool isGroupsRoot() const { return group_id_ == 0; }
+
+ bool isGroup() const { return group_id_ > 0; }
+
+ int groupId() const { return group_id_; }
+
+ /**
+ * Although we don't use this in our custom delegate, we need to
+ * implemented it for our proxy filter model.
+ */
+ QVariant data(int role=Qt::UserRole + 1) const;
+
+ int categoryIndex() const { return cat_index_; }
+
+ /**
+ * Return the number of matched repos when the user types filter text
+ */
+ int matchedReposCount() const;
+
+ void resetMatchedRepoCount() { matched_repos_ = 0; };
+ void setMatchedReposCount(int n) { matched_repos_ = n; };
+ void increaseMatchedRepoCount() { matched_repos_++; };
+
+private:
+ int cat_index_;
+ QString name_;
+ int group_id_;
+ int matched_repos_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_ITEM_H
--- /dev/null
+#include <QTimer>
+#include <QHash>
+#include <QDebug>
+#include <algorithm> // std::sort
+
+#include "api/server-repo.h"
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "main-window.h"
+#include "rpc/rpc-client.h"
+#include "rpc/clone-task.h"
+#include "repo-service.h"
+
+#include "repo-item.h"
+#include "repo-tree-view.h"
+#include "repo-tree-model.h"
+
+namespace {
+
+const int kRefreshLocalReposInterval = 1000;
+const int kMaxRecentUpdatedRepos = 10;
+const int kIndexOfVirtualReposCategory = 2;
+const char *kReadonlyPropertyName = "is-readonly";
+
+bool compareRepoByTimestamp(const ServerRepo& a, const ServerRepo& b)
+{
+ return a.mtime > b.mtime;
+}
+
+QRegExp makeFilterRegExp(const QString& text)
+{
+ return QRegExp(text.split(" ", QString::SkipEmptyParts).join(".*"),
+ Qt::CaseInsensitive);
+}
+
+
+} // namespace
+
+
+RepoTreeModel::RepoTreeModel(QObject *parent)
+ : QStandardItemModel(parent),
+ tree_view_(NULL)
+{
+ initialize();
+
+ refresh_local_timer_ = new QTimer(this);
+ connect(refresh_local_timer_, SIGNAL(timeout()),
+ this, SLOT(refreshLocalRepos()));
+
+ refresh_local_timer_->start(kRefreshLocalReposInterval);
+}
+
+RepoTreeModel::~RepoTreeModel()
+{
+ if (item(kIndexOfVirtualReposCategory) != virtual_repos_category_)
+ delete virtual_repos_category_;
+}
+
+void RepoTreeModel::initialize()
+{
+ recent_updated_category_ = new RepoCategoryItem(CAT_INDEX_RECENT_UPDATED, tr("Recently Updated"));
+ my_repos_category_ = new RepoCategoryItem(CAT_INDEX_MY_REPOS, tr("My Libraries"));
+ virtual_repos_category_ = new RepoCategoryItem(CAT_INDEX_VIRTUAL_REPOS, tr("Sub Libraries"));
+ shared_repos_category_ = new RepoCategoryItem(CAT_INDEX_SHARED_REPOS, tr("Shared with me"));
+ org_repos_category_ = new RepoCategoryItem(CAT_INDEX_SHARED_REPOS, tr("Shared with all"));
+ groups_root_category_ = new RepoCategoryItem(CAT_INDEX_GROUP_REPOS, tr("Shared with groups"), 0);
+ synced_repos_category_ = new RepoCategoryItem(CAT_INDEX_SYNCED_REPOS, tr("Synced Libraries"));
+
+ appendRow(recent_updated_category_);
+ appendRow(my_repos_category_);
+ // appendRow(virtual_repos_category_);
+ appendRow(shared_repos_category_);
+ appendRow(groups_root_category_);
+ appendRow(synced_repos_category_);
+
+ if (tree_view_) {
+ tree_view_->restoreExpandedCategries();
+ }
+}
+
+QModelIndex RepoTreeModel::proxiedIndexFromItem(const QStandardItem* item)
+{
+ QSortFilterProxyModel *proxy_model = (QSortFilterProxyModel *)tree_view_->model();
+ return proxy_model->mapFromSource(indexFromItem(item));
+}
+
+void RepoTreeModel::clear()
+{
+ beginResetModel();
+ QStandardItemModel::clear();
+ initialize();
+ endResetModel();
+}
+
+void RepoTreeModel::setRepos(const std::vector<ServerRepo>& repos)
+{
+ size_t i, n = repos.size();
+ // removeReposDeletedOnServer(repos);
+
+ clear();
+
+ QHash<QString, ServerRepo> map;
+ const Account& account = seafApplet->accountManager()->currentAccount();
+
+ QHash<QString, QString> merged_repo_perms;
+ // If a repo is shared read-only to org and read-write to me (or vice
+ // versa), the final permission should be read-write.
+ for (i = 0; i < n; i++) {
+ ServerRepo repo = repos[i];
+ QString exist_perm, current_perm;
+
+ if (merged_repo_perms.contains(repo.id)) {
+ exist_perm = merged_repo_perms[repo.id];
+ }
+
+ current_perm = repo.permission;
+ if (repo.owner == account.username && repo.permission == "r") {
+ // When the user shares a repo to organization with read-only
+ // permission, the returned repo has permission set to "r", we need
+ // to fix it.
+ current_perm = "rw";
+ }
+
+ if (current_perm == "rw" || exist_perm == "rw") {
+ merged_repo_perms[repo.id] = "rw";
+ } else {
+ merged_repo_perms[repo.id] = "r";
+ }
+
+ // printf("repo: %s, exist_perm: %s, current_perm: %s, final_perm: %s\n",
+ // toCStr(repo.name),
+ // toCStr(exist_perm),
+ // toCStr(current_perm),
+ // toCStr(merged_repo_perms[repo.id]));
+ }
+
+ for (i = 0; i < n; i++) {
+ ServerRepo repo = repos[i];
+ repo.permission = merged_repo_perms[repo.id];
+ // TODO: repo.readonly totally depends on repo.permission, so it should
+ // be a function instead of a variable.
+ repo.readonly = repo.permission == "r";
+
+ if (repo.isPersonalRepo()) {
+ if (!repo.isSubfolder() && !repo.isVirtual()) {
+ checkPersonalRepo(repo);
+ }
+ } else if (repo.isSharedRepo()) {
+ checkSharedRepo(repo);
+ } else if (repo.isOrgRepo()) {
+ checkOrgRepo(repo);
+ } else {
+ checkGroupRepo(repo);
+ }
+
+ if (repo.isSubfolder() || seafApplet->rpcClient()->hasLocalRepo(repo.id))
+ checkSyncedRepo(repo);
+
+ // we have a conflicting case, don't use group version if we can
+ if (map.contains(repo.id) && repo.isGroupRepo())
+ continue;
+ map[repo.id] = repo;
+ }
+
+ QList<ServerRepo> list = map.values();
+ // sort all repos by timestamp
+ // use std::sort for qt containers will force additional copy.
+ // anyway, we can use qt's alternative qSort for it
+ std::stable_sort(list.begin(), list.end(), compareRepoByTimestamp);
+
+ n = qMin(list.size(), kMaxRecentUpdatedRepos);
+ for (i = 0; i < n; i++) {
+ RepoItem *item = new RepoItem(list[i]);
+ recent_updated_category_->appendRow(item);
+ }
+ updateLocalReposPerm(list);
+}
+
+void RepoTreeModel::updateLocalReposPerm(const QList<ServerRepo> &repos)
+{
+ int n = repos.size();
+ for (int i = 0; i < n; i++) {
+ ServerRepo repo = repos[i];
+ if (seafApplet->rpcClient()->hasLocalRepo(repo.id)) {
+ QString readonly_prop;
+ if (seafApplet->rpcClient()->getRepoProperty(
+ repo.id, kReadonlyPropertyName, &readonly_prop) < 0) {
+ continue;
+ }
+ bool readonly = readonly_prop == "true";
+ if (repo.readonly != readonly) {
+ seafApplet->rpcClient()->setRepoProperty(
+ repo.id,
+ kReadonlyPropertyName,
+ repo.readonly ? "true" : "false");
+ qWarning("repo %s %s permission changed to %s",
+ toCStr(repo.id),
+ toCStr(repo.name.left(40)),
+ toCStr(repo.permission));
+ }
+ }
+ }
+}
+
+struct DeleteRepoData {
+ QHash<QString, const ServerRepo*> map;
+ QList<RepoItem*> itemsToDelete;
+};
+
+void RepoTreeModel::collectDeletedRepos(RepoItem *item, void *vdata)
+{
+ DeleteRepoData *data = (DeleteRepoData *)vdata;
+ const ServerRepo* repo = data->map.value(item->repo().id);
+ if (!repo || repo->type != item->repo().type) {
+ data->itemsToDelete << item;
+ }
+}
+
+void RepoTreeModel::removeReposDeletedOnServer(const std::vector<ServerRepo>& repos)
+{
+ int i, n;
+ DeleteRepoData data;
+ n = repos.size();
+ for (i = 0; i < n; i++) {
+ const ServerRepo& repo = repos[i];
+ data.map.insert(repo.id, &repo);
+ }
+
+ forEachRepoItem(&RepoTreeModel::collectDeletedRepos, (void *)&data);
+
+ QListIterator<RepoItem*> iter(data.itemsToDelete);
+ while(iter.hasNext()) {
+ RepoItem *item = iter.next();
+
+ const ServerRepo& repo = item->repo();
+
+ qDebug("remove repo %s(%s) from \"%s\"\n",
+ toCStr(repo.name), toCStr(repo.id),
+ toCStr(((RepoCategoryItem*)item->parent())->name()));
+
+ item->parent()->removeRow(item->row());
+ }
+}
+
+
+void RepoTreeModel::checkPersonalRepo(const ServerRepo& repo)
+{
+ int row, n = my_repos_category_->rowCount();
+ for (row = 0; row < n; row++) {
+ RepoItem *item = (RepoItem *)(my_repos_category_->child(row));
+ if (item->repo().id == repo.id) {
+ updateRepoItem(item, repo);
+ return;
+ }
+ }
+
+ // The repo is new
+ RepoItem *item = new RepoItem(repo);
+ my_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkVirtualRepo(const ServerRepo& repo)
+{
+ if (item(kIndexOfVirtualReposCategory) != virtual_repos_category_) {
+ insertRow(kIndexOfVirtualReposCategory, virtual_repos_category_);
+ }
+
+ int row, n = virtual_repos_category_->rowCount();
+ for (row = 0; row < n; row++) {
+ RepoItem *item = (RepoItem *)(virtual_repos_category_->child(row));
+ if (item->repo().id == repo.id) {
+ updateRepoItem(item, repo);
+ return;
+ }
+ }
+
+ // The repo is new
+ RepoItem *item = new RepoItem(repo);
+ virtual_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkSharedRepo(const ServerRepo& repo)
+{
+ int row, n = shared_repos_category_->rowCount();
+ for (row = 0; row < n; row++) {
+ RepoItem *item = (RepoItem *)(shared_repos_category_->child(row));
+ if (item->repo().id == repo.id) {
+ updateRepoItem(item, repo);
+ return;
+ }
+ }
+
+ // the repo is a new one
+ RepoItem *item = new RepoItem(repo);
+ shared_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkOrgRepo(const ServerRepo& repo)
+{
+ int row, n = org_repos_category_->rowCount();
+ if (invisibleRootItem()->child(3) != org_repos_category_) {
+ // Insert pub repos after "recent updated", "my libraries", "shared libraries"
+ insertRow(3, org_repos_category_);
+ }
+ for (row = 0; row < n; row++) {
+ RepoItem *item = (RepoItem *)(org_repos_category_->child(row));
+ if (item->repo().id == repo.id) {
+ updateRepoItem(item, repo);
+ return;
+ }
+ }
+
+ // the repo is a new one
+ RepoItem *item = new RepoItem(repo);
+ org_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::checkGroupRepo(const ServerRepo &repo)
+{
+ RepoCategoryItem *group = NULL;
+ int row, n = groups_root_category_->rowCount();
+
+ for (row = 0; row < n; row++) {
+ RepoCategoryItem *item =
+ (RepoCategoryItem *)(groups_root_category_->child(row));
+ if (item->groupId() == repo.group_id) {
+ group = item;
+ break;
+ }
+ }
+
+ if (!group) {
+ group = new RepoCategoryItem(
+ CAT_INDEX_GROUP_REPOS, repo.group_name, repo.group_id);
+ group->setLevel(1);
+ groups_root_category_->appendRow(group);
+ }
+
+ // Find the repo in this group
+ n = group->rowCount();
+ for (row = 0; row < n; row++) {
+ RepoItem *item = (RepoItem *)(group->child(row));
+ if (item->repo().id == repo.id) {
+ item->setLevel(2);
+ updateRepoItem(item, repo);
+ return;
+ }
+ }
+
+ // Current repo not in this group yet
+ RepoItem *item = new RepoItem(repo);
+ item->setLevel(2);
+ group->appendRow(item);
+}
+
+void RepoTreeModel::checkSyncedRepo(const ServerRepo& repo)
+{
+ int row, n = synced_repos_category_->rowCount();
+ for (row = 0; row < n; row++) {
+ RepoItem *item = (RepoItem *)(synced_repos_category_->child(row));
+ if (item->repo().id == repo.id) {
+ updateRepoItem(item, repo);
+ return;
+ }
+ }
+
+ // The repo is new
+ RepoItem *item = new RepoItem(repo);
+ synced_repos_category_->appendRow(item);
+}
+
+void RepoTreeModel::updateRepoItem(RepoItem *item, const ServerRepo& repo)
+{
+ item->setRepo(repo);
+}
+
+void RepoTreeModel::forEachRepoItem(void (RepoTreeModel::*func)(RepoItem *, void *),
+ void *data,
+ QStandardItem *item)
+{
+ if (item == nullptr) {
+ item = invisibleRootItem();
+ }
+ if (item->type() == REPO_ITEM_TYPE) {
+ (this->*func)((RepoItem *)item, data);
+ }
+
+ int row, n = item->rowCount();
+ for (row = 0; row < n; row++) {
+ forEachRepoItem(func, data, item->child(row));
+ }
+}
+
+void RepoTreeModel::forEachCategoryItem(void (*func)(RepoCategoryItem *, void *),
+ void *data,
+ QStandardItem *item)
+{
+ if (item == nullptr) {
+ item = invisibleRootItem();
+ }
+ if (item->type() == REPO_CATEGORY_TYPE) {
+ func((RepoCategoryItem *)item, data);
+ }
+
+ int row, n = item->rowCount();
+ for (row = 0; row < n; row++) {
+ forEachCategoryItem(func, data, item->child(row));
+ }
+}
+
+void RepoTreeModel::refreshLocalRepos()
+{
+ if (!seafApplet->mainWindow()->isVisible()) {
+ return;
+ }
+
+ std::vector<CloneTask> tasks;
+ seafApplet->rpcClient()->getCloneTasks(&tasks);
+
+ forEachRepoItem(&RepoTreeModel::refreshRepoItem, (void*) &tasks);
+}
+
+void RepoTreeModel::refreshRepoItem(RepoItem *item, void *data)
+{
+ if (!tree_view_->isExpanded(proxiedIndexFromItem(item->parent()))) {
+ return;
+ }
+
+ if (item->syncNowClicked()) {
+ // Skip refresh repo item on which the user has clicked "sync now"
+ item->setSyncNowClicked(false);
+ return;
+ }
+
+ LocalRepo local_repo;
+ seafApplet->rpcClient()->getLocalRepo(item->repo().id, &local_repo);
+ if (local_repo != item->localRepo()) {
+ // if (local_repo.isValid()) {
+ // printf("local repo of %s changed\n", local_repo.name.toUtf8().data());
+ // }
+ item->setLocalRepo(local_repo);
+ QModelIndex index = indexFromItem(item);
+ emit dataChanged(index,index);
+ emit repoStatusChanged(index);
+ // printf("repo %s is changed\n", toCStr(item->repo().name));
+ }
+
+ item->setCloneTask();
+
+ CloneTask clone_task;
+ std::vector<CloneTask>* tasks = (std::vector<CloneTask>*)data;
+ if (!local_repo.isValid()) {
+ for (size_t i=0; i < tasks->size(); ++i) {
+ clone_task = tasks->at(i);
+ if (clone_task.repo_id == item->repo().id) {
+ item->setCloneTask(clone_task);
+ QModelIndex index = indexFromItem(item);
+ emit dataChanged(index, index);
+ emit repoStatusChanged(index);
+ }
+ }
+ }
+}
+
+void RepoTreeModel::updateRepoItemAfterSyncNow(const QString& repo_id)
+{
+ QString id = repo_id;
+ forEachRepoItem(&RepoTreeModel::updateRepoItemAfterSyncNow, (void*) &id);
+}
+
+void RepoTreeModel::updateRepoItemAfterSyncNow(RepoItem *item, void *data)
+{
+ QString repo_id = *(QString *)data;
+ LocalRepo r = item->localRepo();
+ if (r.isValid() && r.id == repo_id) {
+ // We manually set the sync state of the repo to "SYNC_STATE_ING" to give
+ // the user immediate feedback
+
+ r.setSyncInfo("initializing");
+ r.sync_state = LocalRepo::SYNC_STATE_ING;
+ r.sync_state_str = tr("sync initializing");
+ item->setLocalRepo(r);
+ item->setSyncNowClicked(true);
+ }
+}
+
+void RepoTreeModel::onFilterTextChanged(const QString& text)
+{
+ // Recalculate the matched repos count for each category
+ QStandardItem *root = invisibleRootItem();
+ int row, n;
+ n = root->rowCount();
+ QRegExp re = makeFilterRegExp(text);
+ for (row = 0; row < n; row++) {
+ RepoCategoryItem *category = (RepoCategoryItem *)root->child(row);
+ if (category->isGroupsRoot()) {
+ continue;
+ }
+ int j, total, matched = 0;
+ total = category->rowCount();
+ for (j = 0; j < total; j++) {
+ RepoItem *item = (RepoItem *)category->child(j);
+ if (item->repo().name.contains(re)) {
+ matched++;
+ }
+ }
+ category->setMatchedReposCount(matched);
+ }
+}
+
+RepoFilterProxyModel::RepoFilterProxyModel(QObject *parent)
+ : QSortFilterProxyModel(parent),
+ has_filter_(false)
+{
+}
+
+void RepoFilterProxyModel::setSourceModel(QAbstractItemModel *source_model)
+{
+ QSortFilterProxyModel::setSourceModel(source_model);
+ RepoTreeModel *tree_model = (RepoTreeModel *)source_model;
+ connect(tree_model, SIGNAL(repoStatusChanged(const QModelIndex&)),
+ this, SLOT(onRepoStatusChanged(const QModelIndex&)));
+}
+
+void RepoFilterProxyModel::onRepoStatusChanged(const QModelIndex& source_index)
+{
+ QModelIndex index = mapFromSource(source_index);
+ emit dataChanged(index, index);
+}
+
+bool RepoFilterProxyModel::filterAcceptsRow(int source_row,
+ const QModelIndex & source_parent) const
+{
+ RepoTreeModel *tree_model = (RepoTreeModel *)(sourceModel());
+ QModelIndex index = tree_model->index(source_row, 0, source_parent);
+ QStandardItem *item = tree_model->itemFromIndex(index);
+ if (item->type() == REPO_CATEGORY_TYPE) {
+ // RepoCategoryItem *category = (RepoCategoryItem *)item;
+ // We don't filter repo categories, only filter repos by name.
+ return true;
+ } else if (item->type() == REPO_ITEM_TYPE) {
+ // Use default filtering (filter by item DisplayRole, i.e. repo name)
+ bool match = QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
+ // if (match) {
+ // RepoCategoryItem *category = (RepoCategoryItem *)(item->parent());
+ // }
+ return match;
+ }
+
+ return false;
+}
+
+void RepoFilterProxyModel::setFilterText(const QString& text)
+{
+ has_filter_ = !text.isEmpty();
+ invalidate();
+ setFilterRegExp(makeFilterRegExp(text));
+}
+
+// void RepoFilterProxyModel::sort()
+// {
+// }
+
+bool RepoFilterProxyModel::lessThan(const QModelIndex &left,
+ const QModelIndex &right) const
+{
+ RepoTreeModel *tree_model = (RepoTreeModel *)(sourceModel());
+ QStandardItem *item_l = tree_model->itemFromIndex(left);
+ QStandardItem *item_r = tree_model->itemFromIndex(right);
+
+ /**
+ * When we have filter: sort category by matched repos count
+ * When we have no filter: sort category by category index order
+ *
+ */
+ if (item_l->type() == REPO_CATEGORY_TYPE) {
+ // repo categories
+ RepoCategoryItem *cl = (RepoCategoryItem *)item_l;
+ RepoCategoryItem *cr = (RepoCategoryItem *)item_r;
+ if (has_filter_) {
+ // printf ("%s matched: %d, %s matched: %d\n",
+ // cl->name().toUtf8().data(), cl->matchedReposCount(),
+ // cr->name().toUtf8().data(), cr->matchedReposCount());
+ return cl->matchedReposCount() > cr->matchedReposCount();
+ } else {
+ int cat_l = cl->categoryIndex();
+ int cat_r = cr->categoryIndex();
+ if (cat_l == cat_r) {
+ return cl->name() < cr->name();
+ } else {
+ return cat_l < cat_r;
+ }
+ }
+ } else {
+ // repos
+ RepoItem *cl = (RepoItem *)item_l;
+ RepoItem *cr = (RepoItem *)item_r;
+ if (cl->repo().mtime != cr->repo().mtime) {
+ return cl->repo().mtime > cr->repo().mtime;
+ } else {
+ return cl->repo().name > cr->repo().name;
+ }
+ }
+
+ return false;
+}
+
+Qt::ItemFlags RepoFilterProxyModel::flags(const QModelIndex& index) const
+{
+ Qt::ItemFlags flgs = QSortFilterProxyModel::flags(index);
+ return flgs & ~Qt::ItemIsEditable;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_REPO_TREE_MODEL_H
+#define SEAFILE_CLIENT_REPO_TREE_MODEL_H
+
+#include <vector>
+#include <QStandardItemModel>
+#include <QSortFilterProxyModel>
+#include <QModelIndex>
+
+class ServerRepo;
+class RepoItem;
+class RepoCategoryItem;
+class QTimer;
+class RepoTreeView;
+
+/**
+ * Tree model for repos. There are two levels of items:
+ *
+ * The first level: (RepoCategory)
+ * - My Libraries
+ * - Shared Libraries
+ * - Group 1
+ * - Group 2
+ * - Group N
+ *
+ * The sencond level is the libraries belonging to the first level item (RepoItem)
+ *
+ * - My Libraries
+ * - Notes
+ * - Musics
+ * - Logs
+ */
+class RepoTreeModel : public QStandardItemModel {
+ Q_OBJECT
+
+public:
+ /**
+ * The default sorting order of repo categroies.
+ */
+ enum RepoCategoryIndex {
+ CAT_INDEX_RECENT_UPDATED = 0,
+ CAT_INDEX_MY_REPOS,
+ CAT_INDEX_VIRTUAL_REPOS,
+ CAT_INDEX_SHARED_REPOS,
+ CAT_INDEX_PUBLIC_REPOS,
+ CAT_INDEX_GROUP_REPOS,
+ CAT_INDEX_SYNCED_REPOS,
+ };
+
+ RepoTreeModel(QObject *parent=0);
+ ~RepoTreeModel();
+ void setRepos(const std::vector<ServerRepo>& repos);
+
+ void clear();
+
+ void setTreeView(RepoTreeView *view) { tree_view_ = view; }
+ RepoTreeView* treeView() { return tree_view_; }
+
+ void updateRepoItemAfterSyncNow(const QString& repo_id);
+ void onFilterTextChanged(const QString& text);
+ int repo_category_height;
+
+signals:
+ void repoStatusChanged(const QModelIndex& index);
+
+private slots:
+ void refreshLocalRepos();
+
+private:
+ void checkPersonalRepo(const ServerRepo& repo);
+ void checkVirtualRepo(const ServerRepo& repo);
+ void checkSharedRepo(const ServerRepo& repo);
+ void checkOrgRepo(const ServerRepo& repo);
+ void checkGroupRepo(const ServerRepo& repo);
+ void checkSyncedRepo(const ServerRepo& repo);
+ void initialize();
+ void updateLocalReposPerm(const QList<ServerRepo>& repos);
+ void updateRepoItem(RepoItem *item, const ServerRepo& repo);
+ void refreshRepoItem(RepoItem *item, void *data);
+
+ void forEachRepoItem(void (RepoTreeModel::*func)(RepoItem *, void *),
+ void *data,
+ QStandardItem *root = nullptr);
+
+ void forEachCategoryItem(void (*func)(RepoCategoryItem*, void *),
+ void *data,
+ QStandardItem *root = nullptr);
+
+ void removeReposDeletedOnServer(const std::vector<ServerRepo> &repos);
+
+ void collectDeletedRepos(RepoItem *item, void *vdata);
+ void updateRepoItemAfterSyncNow(RepoItem *item, void *data);
+ QModelIndex proxiedIndexFromItem(const QStandardItem* item);
+
+ RepoCategoryItem *recent_updated_category_;
+ RepoCategoryItem *my_repos_category_;
+ RepoCategoryItem *virtual_repos_category_;
+ RepoCategoryItem *shared_repos_category_;
+ RepoCategoryItem *org_repos_category_;
+ RepoCategoryItem *groups_root_category_;
+ RepoCategoryItem *synced_repos_category_;
+
+ QTimer *refresh_local_timer_;
+
+ RepoTreeView *tree_view_;
+};
+
+/**
+ * This model is used to implement (only show repos filtered by user typed text)
+ */
+class RepoFilterProxyModel : public QSortFilterProxyModel {
+ Q_OBJECT
+public:
+ RepoFilterProxyModel(QObject* parent=0);
+
+ void setSourceModel(QAbstractItemModel *source_model);
+
+ void setFilterText(const QString& text);
+ bool filterAcceptsRow(int source_row,
+ const QModelIndex & source_parent) const;
+ bool lessThan(const QModelIndex &left,
+ const QModelIndex &right) const;
+ Qt::ItemFlags flags(const QModelIndex& index) const;
+
+private slots:
+ void onRepoStatusChanged(const QModelIndex& source_index);
+
+private:
+ bool has_filter_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_TREE_MODEL_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QHeaderView>
+#include <QDesktopServices>
+#include <QEvent>
+#include <QShowEvent>
+#include <QHideEvent>
+#include <QInputDialog>
+#include <Qt>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "settings-mgr.h"
+#include "account-mgr.h"
+#include "rpc/rpc-client.h"
+#include "rpc/local-repo.h"
+#include "download-repo-dialog.h"
+#include "clone-tasks-dialog.h"
+#include "repo-item.h"
+#include "repo-item-delegate.h"
+#include "repo-tree-model.h"
+#include "repo-detail-dialog.h"
+#include "utils/paint-utils.h"
+#include "repo-service.h"
+#include "auto-login-service.h"
+
+#include "filebrowser/file-browser-manager.h"
+#include "filebrowser/file-browser-dialog.h"
+#include "utils/utils-mac.h"
+#include "filebrowser/tasks.h"
+#include "filebrowser/progress-dialog.h"
+#include "ui/set-repo-password-dialog.h"
+#include "ui/private-share-dialog.h"
+#include "ui/check-repo-root-perm-dialog.h"
+
+#include "repo-tree-view.h"
+
+namespace {
+
+const char *kRepoTreeViewSettingsGroup = "RepoTreeView";
+const char *kRepoTreeViewSettingsExpandedCategories = "expandedCategories";
+const char *kSyncIntervalProperty = "sync-interval";
+
+// A Helper Class to copy file
+//
+class FileCopyHelper : public QRunnable {
+public:
+ FileCopyHelper(const QString &source, const QString &target,
+ RepoTreeView *parent)
+ : source_(source),
+ target_(target),
+ parent_(parent) {
+ }
+signals:
+ void success(bool);
+private:
+ void run() {
+ if (!QFile::copy(source_, target_)) {
+ // cannot do GUI operations in this thread
+ // callback to the main thread
+ QMetaObject::invokeMethod(parent_, "copyFileFailed");
+ }
+ }
+ bool autoDelete() {
+ return true;
+ }
+ const QString source_;
+ const QString target_;
+ RepoTreeView *parent_;
+};
+
+FileCopyHelper* copyFile(const QString &source, const QString &target, RepoTreeView *parent) {
+ FileCopyHelper* helper = new FileCopyHelper(source, target, parent);
+ QThreadPool *pool = QThreadPool::globalInstance();
+ pool->start(helper);
+ return helper;
+}
+
+} // anonymous namespace
+
+static ServerRepo selected_repo_;
+// TODO save localrepo as well to avoid many copys
+
+RepoTreeView::RepoTreeView(QWidget *parent)
+ : QTreeView(parent)
+{
+ header()->hide();
+ createActions();
+
+ // We draw the indicator ourselves
+ setIndentation(0);
+ // We handle the click oursevles
+ setExpandsOnDoubleClick(false);
+
+ connect(this, SIGNAL(clicked(const QModelIndex&)),
+ this, SLOT(onItemClicked(const QModelIndex&)));
+
+ connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+#if defined(Q_OS_MAC)
+ this->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+ loadExpandedCategries();
+ connect(qApp, SIGNAL(aboutToQuit()),
+ this, SLOT(saveExpandedCategries()));
+ connect(seafApplet->accountManager(), SIGNAL(beforeAccountSwitched()),
+ this, SLOT(saveExpandedCategries()));
+ connect(seafApplet->accountManager(), SIGNAL(accountsChanged()),
+ this, SLOT(loadExpandedCategries()));
+ connect(seafApplet->settingsManager(), SIGNAL(autoSyncChanged(bool)),
+ this, SLOT(update()));
+
+ setAcceptDrops(true);
+ setDefaultDropAction(Qt::CopyAction);
+ // setAlternatingRowColors(true);
+ setDropIndicatorShown(true);
+
+ current_drop_target_ = QModelIndex();
+ previous_drop_target_ = QModelIndex();
+}
+
+void RepoTreeView::loadExpandedCategries()
+{
+ Account account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ return;
+ }
+ expanded_categroies_.clear();
+ QSettings settings;
+ settings.beginGroup(kRepoTreeViewSettingsGroup);
+ QString key = QString(kRepoTreeViewSettingsExpandedCategories) + "-" + account.getSignature();
+ if (settings.contains(key)) {
+ QString cats = settings.value(key, "").toString();
+ expanded_categroies_ = QSet<QString>::fromList(cats.split("\t", QString::SkipEmptyParts));
+ } else {
+ // Expand "recent updated" on first use
+ expanded_categroies_.insert(tr("Recently Updated"));
+ }
+ settings.endGroup();
+}
+
+void RepoTreeView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPoint pos = event->pos();
+ QModelIndex index = indexAt(pos);
+ if (!index.isValid()) {
+ // Not clicked at a repo item
+ return;
+ }
+
+ QStandardItem *item = getRepoItem(index);
+ if (!item || item->type() != REPO_ITEM_TYPE) {
+ return;
+ }
+ updateRepoActions();
+ QMenu *menu = prepareContextMenu((RepoItem *)item);
+ pos = viewport()->mapToGlobal(pos);
+ menu->exec(pos);
+ menu->deleteLater();
+}
+
+QMenu* RepoTreeView::prepareContextMenu(const RepoItem *item)
+{
+ QMenu *menu = new QMenu(this);
+ if (item->localRepo().isValid()) {
+ menu->addAction(open_local_folder_action_);
+ }
+
+ if (item->repoDownloadable()) {
+ menu->addAction(download_action_);
+ }
+
+ menu->addAction(view_on_web_action_);
+ menu->addAction(open_in_filebrowser_action_);
+
+ if (item->repo().isSharedRepo()) {
+ menu->addAction(unshare_action_);
+ }
+
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ if (account.isPro() && account.username == item->repo().owner) {
+ menu->addSeparator();
+ menu->addAction(share_repo_to_user_action_);
+ menu->addAction(share_repo_to_group_action_);
+ menu->addSeparator();
+ }
+
+ if (item->localRepo().isValid()) {
+ menu->addSeparator();
+ menu->addAction(toggle_auto_sync_action_);
+ menu->addAction(sync_now_action_);
+ menu->addAction(set_sync_interval_action_);
+ menu->addSeparator();
+ }
+
+ menu->addAction(show_detail_action_);
+
+ if (item->cloneTask().isCancelable()) {
+ menu->addAction(cancel_download_action_);
+ }
+ if (item->localRepo().isValid()) {
+ menu->addAction(unsync_action_);
+ menu->addAction(resync_action_);
+ }
+
+ return menu;
+}
+
+void RepoTreeView::updateRepoActions()
+{
+ RepoItem *item = NULL;
+ QItemSelection selected = selectionModel()->selection();
+ QModelIndexList indexes = selected.indexes();
+ if (indexes.size() != 0) {
+ const QModelIndex& index = indexes.at(0);
+ QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+ RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+ QStandardItem *it = tree_model->itemFromIndex(proxy->mapToSource(index));
+ if (it && it->type() == REPO_ITEM_TYPE) {
+ item = (RepoItem *)it;
+ }
+ }
+
+ if (!item) {
+ // No repo item is selected
+ download_action_->setEnabled(false);
+ download_toolbar_action_->setEnabled(false);
+ sync_now_action_->setEnabled(false);
+ open_local_folder_action_->setEnabled(false);
+ open_local_folder_toolbar_action_->setEnabled(false);
+ unsync_action_->setEnabled(false);
+ resync_action_->setEnabled(false);
+ set_sync_interval_action_->setEnabled(false);
+ toggle_auto_sync_action_->setEnabled(false);
+ view_on_web_action_->setEnabled(false);
+ open_in_filebrowser_action_->setEnabled(false);
+ show_detail_action_->setEnabled(false);
+ return;
+ }
+
+ LocalRepo r;
+ seafApplet->rpcClient()->getLocalRepo(item->repo().id, &r);
+ item->setLocalRepo(r);
+
+ if (item->localRepo().isValid()) {
+ const LocalRepo& local_repo = item->localRepo();
+ download_action_->setEnabled(false);
+ download_toolbar_action_->setEnabled(false);
+
+ sync_now_action_->setEnabled(true);
+ sync_now_action_->setData(QVariant::fromValue(local_repo));
+
+ open_local_folder_action_->setData(QVariant::fromValue(local_repo));
+ open_local_folder_action_->setEnabled(true);
+ open_local_folder_toolbar_action_->setData(QVariant::fromValue(local_repo));
+ open_local_folder_toolbar_action_->setEnabled(true);
+
+ unsync_action_->setData(QVariant::fromValue(local_repo));
+ unsync_action_->setEnabled(true);
+
+ resync_action_->setData(QVariant::fromValue(local_repo));
+ resync_action_->setEnabled(true);
+
+ set_sync_interval_action_->setData(QVariant::fromValue(local_repo));
+ set_sync_interval_action_->setEnabled(true);
+
+ if (seafApplet->settingsManager()->autoSync()) {
+ toggle_auto_sync_action_->setData(QVariant::fromValue(local_repo));
+ toggle_auto_sync_action_->setEnabled(true);
+ } else {
+ toggle_auto_sync_action_->setEnabled(false);
+ }
+
+ if (local_repo.auto_sync) {
+ toggle_auto_sync_action_->setText(tr("Disable auto sync"));
+ toggle_auto_sync_action_->setToolTip(tr("Disable auto sync"));
+ toggle_auto_sync_action_->setIcon(QIcon(":/images/pause-gray.png"));
+ } else {
+ toggle_auto_sync_action_->setText(tr("Enable auto sync"));
+ toggle_auto_sync_action_->setToolTip(tr("Enable auto sync"));
+ toggle_auto_sync_action_->setIcon(QIcon(":/images/play-gray.png"));
+ }
+
+ } else {
+ if (item->repoDownloadable()) {
+ download_action_->setEnabled(true);
+ download_toolbar_action_->setEnabled(true);
+ } else {
+ download_action_->setEnabled(false);
+ download_toolbar_action_->setEnabled(false);
+ }
+
+ sync_now_action_->setEnabled(false);
+
+ open_local_folder_action_->setEnabled(false);
+ open_local_folder_toolbar_action_->setEnabled(false);
+ unsync_action_->setEnabled(false);
+ resync_action_->setEnabled(false);
+ set_sync_interval_action_->setEnabled(false);
+ toggle_auto_sync_action_->setEnabled(false);
+ }
+
+ selected_repo_ = item->repo();
+ view_on_web_action_->setEnabled(true);
+ open_in_filebrowser_action_->setEnabled(true);
+
+ show_detail_action_->setEnabled(true);
+
+ if (item->cloneTask().isCancelable()) {
+ cancel_download_action_->setEnabled(true);
+ } else {
+ cancel_download_action_->setEnabled(false);
+ }
+ emit dataChanged(indexes.at(0), indexes.at(0));
+}
+
+QStandardItem* RepoTreeView::getRepoItem(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return NULL;
+ }
+ QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+ RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+ const QModelIndex mapped_index = proxy->mapToSource(index);
+ QStandardItem *item = tree_model->itemFromIndex(mapped_index);
+
+ if (item->type() != REPO_ITEM_TYPE &&
+ item->type() != REPO_CATEGORY_TYPE) {
+ return NULL;
+ }
+ return item;
+}
+
+void RepoTreeView::createActions()
+{
+ show_detail_action_ = new QAction(tr("Show &details"), this);
+ show_detail_action_->setIcon(QIcon(":/images/info-gray.png"));
+ show_detail_action_->setStatusTip(tr("Show details of this library"));
+ show_detail_action_->setIconVisibleInMenu(true);
+ connect(show_detail_action_, SIGNAL(triggered()), this, SLOT(showRepoDetail()));
+
+ download_action_ = new QAction(tr("&Sync this library"), this);
+ download_action_->setIcon(QIcon(":/images/toolbar/download-gray.png"));
+ download_action_->setStatusTip(tr("Sync this library"));
+ download_action_->setIconVisibleInMenu(true);
+ connect(download_action_, SIGNAL(triggered()), this, SLOT(downloadRepo()));
+
+ download_toolbar_action_ = new QAction(tr("&Sync this library"), this);
+ download_toolbar_action_->setIcon(QIcon(":/images/toolbar/download.png"));
+ download_toolbar_action_->setStatusTip(tr("Sync this library"));
+ download_toolbar_action_->setIconVisibleInMenu(false);
+ connect(download_toolbar_action_, SIGNAL(triggered()), this, SLOT(downloadRepo()));
+
+ sync_now_action_ = new QAction(tr("Sync &now"), this);
+ sync_now_action_->setIcon(QIcon(":/images/sync_now-gray.png"));
+ sync_now_action_->setStatusTip(tr("Sync this library immediately"));
+ sync_now_action_->setIconVisibleInMenu(true);
+ connect(sync_now_action_, SIGNAL(triggered()), this, SLOT(syncRepoImmediately()));
+ cancel_download_action_ = new QAction(tr("&Cancel download"), this);
+ cancel_download_action_->setIcon(QIcon(":/images/remove-gray.png"));
+ cancel_download_action_->setStatusTip(tr("Cancel download of this library"));
+ cancel_download_action_->setIconVisibleInMenu(true);
+ connect(cancel_download_action_, SIGNAL(triggered()), this, SLOT(cancelDownload()));
+
+ open_local_folder_action_ = new QAction(tr("&Open local folder"), this);
+ open_local_folder_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+ open_local_folder_action_->setStatusTip(tr("open local folder"));
+ open_local_folder_action_->setIconVisibleInMenu(true);
+ connect(open_local_folder_action_, SIGNAL(triggered()), this, SLOT(openLocalFolder()));
+
+ open_local_folder_toolbar_action_ = new QAction(tr("&Open folder"), this);
+ open_local_folder_toolbar_action_->setIcon(QIcon(":/images/toolbar/file.png"));
+ open_local_folder_toolbar_action_->setStatusTip(tr("open local folder"));
+ open_local_folder_toolbar_action_->setIconVisibleInMenu(true);
+ connect(open_local_folder_toolbar_action_, SIGNAL(triggered()), this, SLOT(openLocalFolder()));
+
+ unsync_action_ = new QAction(tr("&Unsync"), this);
+ unsync_action_->setStatusTip(tr("unsync this library"));
+ unsync_action_->setIcon(QIcon(":/images/minus-gray.png"));
+ unsync_action_->setIconVisibleInMenu(true);
+ connect(unsync_action_, SIGNAL(triggered()), this, SLOT(unsyncRepo()));
+
+ toggle_auto_sync_action_ = new QAction(tr("Enable auto sync"), this);
+ toggle_auto_sync_action_->setStatusTip(tr("Enable auto sync"));
+ toggle_auto_sync_action_->setIconVisibleInMenu(true);
+ connect(toggle_auto_sync_action_, SIGNAL(triggered()), this, SLOT(toggleRepoAutoSync()));
+
+ view_on_web_action_ = new QAction(tr("&View on cloud"), this);
+ view_on_web_action_->setIcon(QIcon(":/images/cloud-gray.png"));
+ view_on_web_action_->setStatusTip(tr("view this library on seahub"));
+ view_on_web_action_->setIconVisibleInMenu(true);
+
+ connect(view_on_web_action_, SIGNAL(triggered()), this, SLOT(viewRepoOnWeb()));
+
+ share_repo_to_user_action_ = new QAction(tr("Share to user"), this);
+ share_repo_to_user_action_->setIcon(QIcon(":/images/share.png"));
+ share_repo_to_user_action_->setStatusTip(tr("Share this library to a user"));
+ share_repo_to_user_action_->setIconVisibleInMenu(true);
+
+ connect(share_repo_to_user_action_, SIGNAL(triggered()), this, SLOT(shareRepoToUser()));
+
+ share_repo_to_group_action_ = new QAction(tr("Share to group"), this);
+ share_repo_to_group_action_->setIcon(QIcon(":/images/share.png"));
+ share_repo_to_group_action_->setStatusTip(tr("Share this library to a group"));
+ share_repo_to_group_action_->setIconVisibleInMenu(true);
+
+ connect(share_repo_to_group_action_, SIGNAL(triggered()), this, SLOT(shareRepoToGroup()));
+
+ QString open_action_text = tr("&Open cloud file browser");
+ if (open_action_text.contains("%")) {
+ // In German translation there is a "seafile" string, so need to use tr("..").arg(..) here
+ open_action_text = open_action_text.arg(getBrand());
+ }
+
+ open_in_filebrowser_action_ = new QAction(open_action_text, this);
+ open_in_filebrowser_action_->setIcon(QIcon(":/images/cloud-gray.png"));
+ open_in_filebrowser_action_->setStatusTip(tr("open this library in embedded Cloud File Browser"));
+ open_in_filebrowser_action_->setIconVisibleInMenu(true);
+
+ connect(open_in_filebrowser_action_, SIGNAL(triggered()), this, SLOT(openInFileBrowser()));
+
+ unshare_action_ = new QAction(tr("&Leave share"), this);
+ unshare_action_->setIcon(QIcon(":/images/leave-share.png"));
+ unshare_action_->setStatusTip(tr("leave share"));
+
+ connect(unshare_action_, SIGNAL(triggered()), this, SLOT(unshareRepo()));
+
+ resync_action_ = new QAction(tr("&Resync this library"), this);
+ resync_action_->setIcon(QIcon(":/images/resync.png"));
+ resync_action_->setStatusTip(tr("unsync and resync this library"));
+
+ connect(resync_action_, SIGNAL(triggered()), this, SLOT(resyncRepo()));
+
+ set_sync_interval_action_ = new QAction(tr("Set sync &Interval"), this);
+ set_sync_interval_action_->setIcon(QIcon(":/images/clock.png"));
+ set_sync_interval_action_->setStatusTip(tr("set sync interval for this library"));
+
+ connect(set_sync_interval_action_, SIGNAL(triggered()), this, SLOT(setRepoSyncInterval()));
+}
+
+void RepoTreeView::downloadRepo()
+{
+ DownloadRepoDialog dialog(seafApplet->accountManager()->currentAccount(), selected_repo_, QString(), this);
+
+ dialog.exec();
+
+ updateRepoActions();
+}
+
+void RepoTreeView::showRepoDetail()
+{
+ RepoDetailDialog dialog(selected_repo_, this);
+ dialog.exec();
+}
+
+void RepoTreeView::openLocalFolder()
+{
+ LocalRepo repo = qvariant_cast<LocalRepo>(open_local_folder_action_->data());
+ QDesktopServices::openUrl(QUrl::fromLocalFile(repo.worktree));
+}
+
+void RepoTreeView::toggleRepoAutoSync()
+{
+ LocalRepo repo = qvariant_cast<LocalRepo>(toggle_auto_sync_action_->data());
+
+ seafApplet->rpcClient()->setRepoAutoSync(repo.id, !repo.auto_sync);
+
+ updateRepoActions();
+}
+
+void RepoTreeView::unsyncRepo()
+{
+ LocalRepo repo = qvariant_cast<LocalRepo>(toggle_auto_sync_action_->data());
+
+ QString question = tr("Are you sure to unsync the library \"%1\"?").arg(repo.name);
+
+ if (!seafApplet->yesOrCancelBox(question, this, false)) {
+ return;
+ }
+
+ unsyncRepoImpl(repo);
+}
+
+void RepoTreeView::unsyncRepoImpl(const LocalRepo& repo)
+{
+ if (seafApplet->rpcClient()->unsync(repo.id) < 0) {
+ seafApplet->warningBox(tr("Failed to unsync library \"%1\"").arg(repo.name), this);
+ }
+ ServerRepo server_repo = RepoService::instance()->getRepo(repo.id);
+ if (server_repo.isValid() && server_repo.isSubfolder())
+ RepoService::instance()->removeSyncedSubfolder(repo.id);
+
+ updateRepoActions();
+}
+
+void RepoTreeView::onItemClicked(const QModelIndex& index)
+{
+ QStandardItem *item = getRepoItem(index);
+ if (!item) {
+ return;
+ }
+ if (item->type() == REPO_ITEM_TYPE) {
+ return;
+ } else {
+ // A repo category item
+ if (isExpanded(index)) {
+ collapse(index);
+ } else {
+ expand(index);
+ }
+ }
+}
+
+void RepoTreeView::onItemDoubleClicked(const QModelIndex& index)
+{
+ QStandardItem *item = getRepoItem(index);
+ if (!item) {
+ return;
+ }
+ if (item->type() == REPO_ITEM_TYPE) {
+ RepoItem *it = (RepoItem *)item;
+ const LocalRepo& local_repo = it->localRepo();
+ if (local_repo.isValid()) {
+ // open local folder for downloaded repo
+ QDesktopServices::openUrl(QUrl::fromLocalFile(local_repo.worktree));
+ } else {
+ // open seahub repo page for not downloaded repo
+ FileBrowserManager::getInstance()->openOrActivateDialog(
+ seafApplet->accountManager()->currentAccount(),
+ it->repo());
+ }
+ }
+}
+
+void RepoTreeView::viewRepoOnWeb()
+{
+ const Account account = seafApplet->accountManager()->currentAccount();
+ if (account.isValid()) {
+ // we adopt a new format of cloud view url from server version 4.2.0
+ if (!account.isAtLeastVersion(4, 2, 0)) {
+ QDesktopServices::openUrl(account.getAbsoluteUrl("repo/" + selected_repo_.id));
+ } else {
+ AutoLoginService::instance()->startAutoLogin("/library/" + selected_repo_.id + "/" + selected_repo_.name + "/");
+ }
+ }
+}
+
+void RepoTreeView::shareRepo(bool to_group)
+{
+ const Account account = seafApplet->accountManager()->currentAccount();
+ PrivateShareDialog dialog(account, selected_repo_.id, selected_repo_.name,
+ "/", to_group,
+ this);
+ dialog.exec();
+}
+
+void RepoTreeView::shareRepoToUser()
+{
+ shareRepo(false);
+}
+
+void RepoTreeView::shareRepoToGroup()
+{
+ shareRepo(true);
+}
+
+void RepoTreeView::unshareRepo()
+{
+ if (!seafApplet->yesOrNoBox(
+ tr("Are you sure you want to leave the share \"%1\"?").arg(
+ selected_repo_.name), this, false)) {
+ return;
+ }
+
+ const Account account = seafApplet->accountManager()->currentAccount();
+ const QString repo_id = selected_repo_.id;
+ const QString from_user = selected_repo_.owner;
+ UnshareRepoRequest* request =
+ new UnshareRepoRequest(account, repo_id, from_user);
+
+ connect(request, SIGNAL(success()),
+ this, SLOT(onUnshareSuccess()));
+ connect(request, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onUnshareFailed(const ApiError&)));
+
+ request->send();
+}
+
+void RepoTreeView::onUnshareSuccess()
+{
+ RepoService::instance()->refresh(true);
+
+ UnshareRepoRequest* req = qobject_cast<UnshareRepoRequest*>(sender());
+ if (!req) {
+ return;
+ } else {
+ req->deleteLater();
+ }
+
+ LocalRepo local_repo;
+ seafApplet->rpcClient()->getLocalRepo(req->repoId(), &local_repo);
+ if (local_repo.isValid()) {
+ unsyncRepoImpl(local_repo);
+ }
+}
+
+void RepoTreeView::onUnshareFailed(const ApiError&error)
+{
+ seafApplet->warningBox(tr("Leaving share failed"), this);
+}
+
+void RepoTreeView::openInFileBrowser()
+{
+ const Account account = seafApplet->accountManager()->currentAccount();
+ if (account.isValid()) {
+ FileBrowserManager::getInstance()->openOrActivateDialog(
+ seafApplet->accountManager()->currentAccount(),
+ selected_repo_);
+ }
+}
+
+bool RepoTreeView::viewportEvent(QEvent *event)
+{
+ if (event->type() != QEvent::ToolTip &&
+ event->type() != QEvent::WhatsThis &&
+ event->type() != QEvent::MouseButtonPress &&
+ event->type() != QEvent::MouseButtonRelease)
+ {
+ return QTreeView::viewportEvent(event);
+ }
+
+ QPoint global_pos = QCursor::pos();
+ QPoint viewport_pos = viewport()->mapFromGlobal(global_pos);
+ QModelIndex index = indexAt(viewport_pos);
+ if (!index.isValid()) {
+ return true;
+ }
+
+ QStandardItem *item = getRepoItem(index);
+ if (!item) {
+ return true;
+ }
+
+ // handle the event in the top
+ const QModelIndex top_index = indexAt(QPoint(0, 0));
+ if (event->type() == QEvent::MouseButtonPress ||
+ event->type() == QEvent::MouseButtonRelease)
+ {
+ QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+ RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+
+ if (index == top_index &&
+ top_index.parent().isValid() &&
+ viewport_pos.y() <= tree_model->repo_category_height)
+ {
+ QMouseEvent *ev = static_cast<QMouseEvent*>(event);
+ if (!(ev->buttons() & Qt::LeftButton)) {
+ return true;
+ } else {
+ const QModelIndex parent = top_index.parent();
+ setExpanded(parent, !isExpanded(parent));
+ return true;
+ }
+ }
+ return QTreeView::viewportEvent(event);
+ }
+
+ QRect item_rect = visualRect(index);
+ if (item->type() == REPO_ITEM_TYPE) {
+ showRepoItemToolTip((RepoItem *)item, global_pos, item_rect);
+ } else {
+ showRepoCategoryItemToolTip((RepoCategoryItem *)item, global_pos, item_rect);
+ }
+
+ return true;
+}
+
+void RepoTreeView::showRepoItemToolTip(const RepoItem *item,
+ const QPoint& pos,
+ const QRect& rect)
+{
+ RepoItemDelegate *delegate = (RepoItemDelegate *)itemDelegate();
+ delegate->showRepoItemToolTip(item, pos, viewport(), rect);
+}
+
+void RepoTreeView::showRepoCategoryItemToolTip(const RepoCategoryItem *item,
+ const QPoint& pos,
+ const QRect& rect)
+{
+ QToolTip::showText(pos, item->name(), viewport(), rect);
+ // QToolTip::showText(pos, item->name());
+}
+
+std::vector<QAction*> RepoTreeView::getToolBarActions()
+{
+ std::vector<QAction*> actions;
+
+ updateRepoActions();
+
+ actions.push_back(download_toolbar_action_);
+ actions.push_back(open_local_folder_toolbar_action_);
+ return actions;
+}
+
+void RepoTreeView::selectionChanged(const QItemSelection &selected,
+ const QItemSelection &deselected)
+{
+ updateRepoActions();
+}
+
+void RepoTreeView::hideEvent(QHideEvent *event)
+{
+ download_action_->setEnabled(false);
+ download_toolbar_action_->setEnabled(false);
+ open_local_folder_action_->setEnabled(false);
+ open_local_folder_toolbar_action_->setEnabled(false);
+ unsync_action_->setEnabled(false);
+ resync_action_->setEnabled(false);
+ set_sync_interval_action_->setEnabled(false);
+ toggle_auto_sync_action_->setEnabled(false);
+ view_on_web_action_->setEnabled(false);
+ open_in_filebrowser_action_->setEnabled(false);
+ show_detail_action_->setEnabled(false);
+}
+
+void RepoTreeView::saveExpandedCategries()
+{
+ Account account = seafApplet->accountManager()->currentAccount();
+ if (!account.isValid()) {
+ return;
+ }
+ QSettings settings;
+ QStringList cats = expanded_categroies_.toList();
+ settings.beginGroup(kRepoTreeViewSettingsGroup);
+ QString key = QString(kRepoTreeViewSettingsExpandedCategories) + "-" + account.getSignature();
+ settings.setValue(key, cats.join("\t"));
+ settings.endGroup();
+}
+
+void RepoTreeView::showEvent(QShowEvent *event)
+{
+ updateRepoActions();
+}
+
+void RepoTreeView::syncRepoImmediately()
+{
+ LocalRepo repo = qvariant_cast<LocalRepo>(sync_now_action_->data());
+
+ seafApplet->rpcClient()->syncRepoImmediately(repo.id);
+
+ QSortFilterProxyModel *proxy = (QSortFilterProxyModel *)model();
+ RepoTreeModel *tree_model = (RepoTreeModel *)(proxy->sourceModel());
+ tree_model->updateRepoItemAfterSyncNow(repo.id);
+}
+
+void RepoTreeView::cancelDownload()
+{
+ QString error;
+ if (seafApplet->rpcClient()->cancelCloneTask(selected_repo_.id, &error) < 0) {
+ seafApplet->warningBox(tr("Failed to cancel this task:\n\n %1").arg(error), this);
+ } else {
+ seafApplet->messageBox(tr("The download has been canceled"), this);
+ }
+}
+
+void RepoTreeView::expand(const QModelIndex& index, bool remember)
+{
+ QTreeView::expand(index);
+ if (remember) {
+ QStandardItem *item = getRepoItem(index);
+ if (item->type() == REPO_CATEGORY_TYPE) {
+ expanded_categroies_.insert(item->data(Qt::DisplayRole).toString());
+ }
+ }
+}
+
+void RepoTreeView::collapse(const QModelIndex& index, bool remember)
+{
+ QTreeView::collapse(index);
+ if (remember) {
+ QStandardItem *item = getRepoItem(index);
+ if (item->type() == REPO_CATEGORY_TYPE) {
+ expanded_categroies_.remove(item->data(Qt::DisplayRole).toString());
+ }
+ }
+}
+
+void RepoTreeView::restoreExpandedCategries()
+{
+ QSortFilterProxyModel *proxy_model =
+ (QSortFilterProxyModel *)(this->model());
+ RepoTreeModel *tree_model = (RepoTreeModel *)(proxy_model->sourceModel());
+
+ for (int i = 0; i < proxy_model->rowCount(); i++) {
+ QModelIndex index = proxy_model->index(i, 0);
+ QString category = proxy_model->data(index).toString();
+ if (expanded_categroies_.contains(category)) {
+ expand(index, false);
+ } else {
+ collapse(index, false);
+ }
+
+ QStandardItem *item =
+ tree_model->itemFromIndex(proxy_model->mapToSource(index));
+
+ // We need to go one level down if this item is the groups root.
+ if (item->type() == REPO_CATEGORY_TYPE &&
+ ((RepoCategoryItem *)item)->isGroupsRoot()) {
+ for (int j = 0; j < item->rowCount(); j++) {
+ RepoCategoryItem *category_item =
+ (RepoCategoryItem *)(item->child(j));
+ QModelIndex index = proxy_model->mapFromSource(
+ tree_model->indexFromItem(category_item));
+ QString category = proxy_model->data(index).toString();
+ if (expanded_categroies_.contains(category)) {
+ expand(index, false);
+ } else {
+ collapse(index, false);
+ }
+ }
+ }
+ }
+}
+
+void RepoTreeView::resyncRepo()
+{
+ LocalRepo local_repo = qvariant_cast<LocalRepo>(unsync_action_->data());
+ ServerRepo server_repo = RepoService::instance()->getRepo(local_repo.id);
+
+ SeafileRpcClient *rpc = seafApplet->rpcClient();
+
+ if (!seafApplet->yesOrNoBox(
+ tr("Are you sure to resync the library \"%1\"?").arg(server_repo.name),
+ this)) {
+ return;
+ }
+
+ if (rpc->unsync(server_repo.id) < 0) {
+ seafApplet->warningBox(tr("Failed to unsync library \"%1\"").arg(server_repo.name));
+ return;
+ }
+
+ DownloadRepoDialog dialog(seafApplet->accountManager()->currentAccount(),
+ RepoService::instance()->getRepo(server_repo.id), QString(), this);
+ dialog.setMergeWithExisting(QFileInfo(local_repo.worktree).dir().absolutePath());
+ if (!server_repo.encrypted) {
+ dialog.setResyncMode();
+ }
+
+ dialog.exec();
+ updateRepoActions();
+}
+
+void RepoTreeView::dropEvent(QDropEvent *event)
+{
+ const QModelIndex index = indexAt(event->pos());
+ QStandardItem *standard_item = getRepoItem(index);
+ if (!standard_item || standard_item->type() != REPO_ITEM_TYPE) {
+ return;
+ }
+ event->accept();
+
+ RepoItem *item = static_cast<RepoItem*>(standard_item);
+ const ServerRepo &repo = item->repo();
+
+ updateDropTarget(QModelIndex());
+
+ const QUrl url = event->mimeData()->urls().at(0);
+ QString local_path = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+ local_path = utils::mac::fix_file_id_url(local_path);
+#endif
+
+ if (repo.readonly) {
+ // Do not call the `show` method of the dialog. It would show itself if
+ // the task doens't finish within 4 seconds.
+ //
+ // This is also why we can't create the dialog object on stack and use
+ // `dialog.exec()`.
+ CheckRepoRootDirPermDialog *dialog = new CheckRepoRootDirPermDialog(
+ seafApplet->accountManager()->currentAccount(), repo, local_path, this);
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ connect(dialog, SIGNAL(finished(int)), this, SLOT(checkRootPermDone()));
+ } else {
+ uploadDroppedFile(repo, local_path);
+ }
+}
+
+void RepoTreeView::checkRootPermDone()
+{
+ CheckRepoRootDirPermDialog *dialog = qobject_cast<CheckRepoRootDirPermDialog *>(sender());
+ if (dialog->hasWritePerm()) {
+ uploadDroppedFile(dialog->repo(), dialog->localPath());
+ } else {
+ seafApplet->warningBox(tr("You do not have permission to upload to this folder"));
+ }
+}
+
+void RepoTreeView::uploadDroppedFile(const ServerRepo& repo, const QString& local_path)
+{
+ const QString file_name = QFileInfo(local_path).fileName();
+ // if the repo is synced
+ LocalRepo local_repo;
+ if (seafApplet->rpcClient()->getLocalRepo(repo.id, &local_repo) >= 0) {
+ QString target_path = QDir(local_repo.worktree).absoluteFilePath(file_name);
+ if (QFileInfo(target_path) == QFileInfo(local_path)) {
+ seafApplet->warningBox(tr("Unable to overwrite file \"%1\" with itself").arg(file_name));
+ return;
+ }
+
+ if (QFileInfo(target_path).exists()) {
+ if (!seafApplet->yesOrNoBox(tr("Are you sure to overwrite the file \"%1\"").arg(file_name)))
+ return;
+ if (!QFile(target_path).remove()) {
+ seafApplet->warningBox(tr("Unable to delete file \"%1\"").arg(file_name));
+ return;
+ }
+ }
+
+ copyFile(local_path, target_path, this);
+
+ return;
+ }
+
+ FileUploadTask *task = new FileUploadTask(seafApplet->accountManager()->currentAccount(),
+ repo.id, "/", local_path, file_name);
+ uploadFileStart(task);
+}
+
+void RepoTreeView::dragMoveEvent(QDragMoveEvent *event)
+{
+ QPoint pos = event->pos();
+ const QModelIndex index = indexAt(pos);
+ QRect rect = visualRect(index);
+
+ // highlight the selected item, and dehightlight when it's over
+ QStandardItem *item = getRepoItem(index);
+ if (item && item->type() == REPO_ITEM_TYPE) {
+ if (changeGrayBackground(pos, rect)) {
+ updateDropTarget(index);
+ event->setDropAction(Qt::CopyAction);
+ event->accept();
+ } else {
+ updateDropTarget(QModelIndex());
+ event->setDropAction(Qt::IgnoreAction);
+ event->accept();
+ }
+ } else {
+ event->setDropAction(Qt::IgnoreAction);
+ event->accept();
+ return;
+ }
+}
+
+void RepoTreeView::dragLeaveEvent(QDragLeaveEvent *event)
+{
+ updateDropTarget(QModelIndex());
+ QTreeView::dragLeaveEvent(event);
+}
+
+void RepoTreeView::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) {
+ const QUrl url = event->mimeData()->urls().at(0);
+ if (url.scheme() == "file") {
+
+ QString file_name = url.toLocalFile();
+#if defined(Q_OS_MAC) && (QT_VERSION <= QT_VERSION_CHECK(5, 4, 0))
+ file_name = utils::mac::fix_file_id_url(file_name);
+#endif
+
+ if (QFileInfo(file_name).isFile()) {
+ event->setDropAction(Qt::CopyAction);
+ event->accept();
+ }
+ }
+ }
+}
+
+bool RepoTreeView::changeGrayBackground(
+ const QPoint& pos, const QRect& rect) const
+{
+ const int margin = 2;
+ if ((pos.y() - rect.top() > margin) &&
+ (rect.bottom() - pos.y() > margin)) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void RepoTreeView::updateBackground()
+{
+ if (current_drop_target_.isValid()) {
+ dataChanged(current_drop_target_, current_drop_target_,
+ QVector<int>(1, Qt::BackgroundRole));
+ }
+
+ if (previous_drop_target_.isValid()) {
+ dataChanged(previous_drop_target_, previous_drop_target_,
+ QVector<int>(1, Qt::BackgroundRole));
+ }
+}
+
+void RepoTreeView::updateDropTarget(const QModelIndex& index)
+{
+ previous_drop_target_ = current_drop_target_;
+ if (index.isValid() && index == current_drop_target_) {
+ // No need to repaint since the cursor is still with in the same repo
+ // item.
+ return;
+ }
+
+ current_drop_target_ = index;
+ updateBackground();
+}
+
+void RepoTreeView::uploadFileStart(FileUploadTask *task)
+{
+ connect(task, SIGNAL(finished(bool)),
+ this, SLOT(uploadFileFinished(bool)));
+ FileBrowserProgressDialog *dialog = new FileBrowserProgressDialog(task, this);
+
+ dialog->setAttribute(Qt::WA_DeleteOnClose);
+ dialog->show();
+ const QPoint global = this->mapToGlobal(rect().center());
+ dialog->move(global.x() - dialog->width() / 2,
+ global.y() - dialog->height() / 2);
+ dialog->raise();
+ dialog->activateWindow();
+
+ task->start();
+}
+
+void RepoTreeView::uploadFileFinished(bool success)
+{
+ FileUploadTask *task = qobject_cast<FileUploadTask *>(sender());
+ if (task == NULL)
+ return;
+
+ if (!success) {
+ // if the user cancel the task, don't bother him(or her) with it
+ if (task->error() == FileNetworkTask::TaskCanceled)
+ return;
+ // failed and it is a encrypted repository
+ ServerRepo repo = RepoService::instance()->getRepo(task->repoId());
+ if (repo.encrypted && task->httpErrorCode() == 400) {
+ SetRepoPasswordDialog password_dialog(repo, this);
+ if (password_dialog.exec()) {
+ FileUploadTask *new_task = new FileUploadTask(*task);
+ uploadFileStart(new_task);
+ }
+ return;
+ }
+
+ QString msg = tr("Failed to upload file: %1").arg(task->errorString());
+ seafApplet->warningBox(msg, this);
+ }
+}
+
+void RepoTreeView::copyFileFailed()
+{
+ QString msg = QObject::tr("copy failed");
+ seafApplet->warningBox(msg);
+}
+
+void RepoTreeView::setRepoSyncInterval()
+{
+ LocalRepo local_repo =
+ qvariant_cast<LocalRepo>(set_sync_interval_action_->data());
+
+ int default_interval = 0;
+
+ QString value;
+ if (seafApplet->rpcClient()->getRepoProperty(
+ local_repo.id, kSyncIntervalProperty, &value) == 0) {
+ default_interval = value.toInt();
+ }
+
+ QInputDialog dialog(this);
+ dialog.setInputMode(QInputDialog::IntInput);
+ dialog.setIntMinimum(0);
+ dialog.setIntMaximum(2147483647);
+ dialog.setIntStep(10);
+ dialog.setIntValue(default_interval);
+ dialog.setObjectName("syncIntervalDialog");
+ dialog.setLabelText(tr("Sync Interval (In seconds):"));
+ dialog.setWindowTitle(
+ tr("Set Sync Internval For Library \"%1\"").arg(local_repo.name));
+ dialog.setWindowIcon(QIcon(":/images/seafile.png"));
+ dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ dialog.resize(400, 100);
+ if (dialog.exec() != QDialog::Accepted) {
+ return;
+ }
+ int interval = dialog.intValue();
+
+ if (interval != 0 && interval == default_interval) {
+ return;
+ }
+
+ seafApplet->rpcClient()->setRepoProperty(
+ local_repo.id, kSyncIntervalProperty, QString::number(interval));
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_REPO_TREE_VIEW_H
+#define SEAFILE_CLIENT_REPO_TREE_VIEW_H
+
+#include <vector>
+#include <QTreeView>
+#include <QSet>
+
+class QAction;
+class QContextMenuEvent;
+class QEvent;
+class QShowEvent;
+class QHideEvent;
+class QModelIndex;
+class QStandardItem;
+
+class RepoItem;
+class RepoCategoryItem;
+class ServerRepo;
+class LocalRepo;
+
+class ApiError;
+class CloneTasksDialog;
+class FileUploadTask;
+
+class RepoTreeView : public QTreeView {
+ Q_OBJECT
+public:
+ RepoTreeView(QWidget *parent=0);
+
+ std::vector<QAction*> getToolBarActions();
+
+ void expand(const QModelIndex& index, bool remember=true);
+ void collapse(const QModelIndex& index, bool remember=true);
+
+ /**
+ * Restore the expanded repo categories when:
+ * 1. applet startup
+ * 1. restore from filtering repos
+ */
+ void restoreExpandedCategries();
+ const QModelIndex getCurrentDropTarget() const
+ { return current_drop_target_; }
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *event);
+ bool viewportEvent(QEvent *event);
+ void showEvent(QShowEvent *event);
+ void hideEvent(QHideEvent *event);
+ void selectionChanged(const QItemSelection &selected,
+ const QItemSelection &deselected);
+
+private slots:
+ void downloadRepo();
+ void showRepoDetail();
+ void openLocalFolder();
+ void viewRepoOnWeb();
+ void shareRepoToUser();
+ void shareRepoToGroup();
+ void unshareRepo();
+ void onUnshareSuccess();
+ void onUnshareFailed(const ApiError& error);
+ void openInFileBrowser();
+ void onItemClicked(const QModelIndex& index);
+ void onItemDoubleClicked(const QModelIndex& index);
+ void toggleRepoAutoSync();
+ void unsyncRepo();
+ void syncRepoImmediately();
+ void cancelDownload();
+ void loadExpandedCategries();
+ void saveExpandedCategries();
+ void resyncRepo();
+ void setRepoSyncInterval();
+
+ void checkRootPermDone();
+ void uploadFileStart(FileUploadTask *task);
+ void uploadFileFinished(bool success);
+ void copyFileFailed();
+
+private:
+ QStandardItem* getRepoItem(const QModelIndex &index) const;
+
+ void createActions();
+ QMenu *prepareContextMenu(const RepoItem *item);
+ void updateRepoActions();
+
+ void showRepoItemToolTip(const RepoItem *item,
+ const QPoint& pos,
+ const QRect& rect);
+
+ void showRepoCategoryItemToolTip(const RepoCategoryItem *item,
+ const QPoint& pos,
+ const QRect& rect);
+
+ void dropEvent(QDropEvent *event);
+ void dragMoveEvent(QDragMoveEvent *event);
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dragLeaveEvent(QDragLeaveEvent *event);
+ bool changeGrayBackground(const QPoint& pos,
+ const QRect& rect) const;
+ void updateBackground();
+ void updateDropTarget(const QModelIndex& index);
+ void shareRepo(bool to_group);
+ void uploadDroppedFile(const ServerRepo& repo, const QString& path);
+ void unsyncRepoImpl(const LocalRepo& repo);
+
+ QAction *download_action_;
+ QAction *download_toolbar_action_;
+ QAction *show_detail_action_;
+ QAction *open_local_folder_action_;
+ QAction *open_local_folder_toolbar_action_;
+ QAction *unsync_action_;
+ QAction *view_on_web_action_;
+ QAction *share_repo_to_user_action_;
+ QAction *share_repo_to_group_action_;
+ QAction *open_in_filebrowser_action_;
+ QAction *unshare_action_;
+ QAction *toggle_auto_sync_action_;
+ QAction *sync_now_action_;
+ QAction *cancel_download_action_;
+ QAction *resync_action_;
+ QAction *set_sync_interval_action_;
+
+ QSet<QString> expanded_categroies_;
+
+ QModelIndex current_drop_target_;
+ QModelIndex previous_drop_target_;
+};
+
+#endif // SEAFILE_CLIENT_REPO_TREE_VIEW_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QTimer>
+#include <QStackedWidget>
+#include <QSortFilterProxyModel>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "repo-tree-view.h"
+#include "repo-tree-model.h"
+#include "repo-item-delegate.h"
+#include "api/requests.h"
+#include "api/server-repo.h"
+#include "rpc/local-repo.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "QtAwesome.h"
+#include "ui/search-bar.h"
+
+#include "repos-tab.h"
+
+namespace {
+
+const char *kLoadingFaieldLabelName = "loadingFailedText";
+
+enum {
+ INDEX_LOADING_VIEW = 0,
+ INDEX_LOADING_FAILED_VIEW,
+ INDEX_LOGOUT_VIEW,
+ INDEX_REPOS_VIEW
+};
+
+} // namespace
+
+ReposTab::ReposTab(QWidget *parent)
+ : TabView(parent)
+{
+ createRepoTree();
+ createLoadingView();
+ createLoadingFailedView();
+
+ //createLogoutView
+ logout_view_ = new LogoutView;
+ static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+ filter_text_ = new SearchBar;
+ filter_text_->setPlaceholderText(tr("Search libraries"));
+ connect(filter_text_, SIGNAL(textChanged(const QString&)),
+ this, SLOT(onFilterTextChanged(const QString&)));
+
+ QVBoxLayout *vlayout = (QVBoxLayout *)layout();
+ vlayout->setSpacing(0);
+ vlayout->insertWidget(0, filter_text_);
+
+ mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+ mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+ mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+ mStack->insertWidget(INDEX_REPOS_VIEW, repos_tree_);
+
+ RepoService *svc = RepoService::instance();
+
+ connect(svc, SIGNAL(refreshSuccess(const std::vector<ServerRepo>&)),
+ this, SLOT(refreshRepos(const std::vector<ServerRepo>&)));
+ connect(svc, SIGNAL(refreshFailed(const ApiError&)),
+ this, SLOT(refreshReposFailed(const ApiError&)));
+
+ refresh();
+}
+
+void ReposTab::createRepoTree()
+{
+ repos_tree_ = new RepoTreeView(this);
+ repos_model_ = new RepoTreeModel(this);
+ repos_model_->setTreeView(repos_tree_);
+
+ filter_model_ = new RepoFilterProxyModel(this);
+ filter_model_->setSourceModel(repos_model_);
+ filter_model_->setDynamicSortFilter(true);
+ repos_tree_->setModel(filter_model_);
+ repos_tree_->setItemDelegate(new RepoItemDelegate(repos_tree_));
+}
+
+void ReposTab::createLoadingView()
+{
+ loading_view_ = new LoadingView;
+ static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void ReposTab::createLoadingFailedView()
+{
+ loading_failed_view_ = new QWidget(this);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ loading_failed_view_->setLayout(layout);
+
+ QLabel *label = new QLabel;
+ label->setObjectName(kLoadingFaieldLabelName);
+ QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+ QString label_text = tr("Failed to get libraries information<br/>"
+ "Please %1").arg(link);
+ label->setText(label_text);
+ label->setAlignment(Qt::AlignCenter);
+
+ connect(label, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(refresh()));
+
+ layout->addWidget(label);
+}
+
+void ReposTab::refreshRepos(const std::vector<ServerRepo>& repos)
+{
+ repos_model_->setRepos(repos);
+ onFilterTextChanged(filter_text_->text());
+ filter_text_->setVisible(true);
+ mStack->setCurrentIndex(INDEX_REPOS_VIEW);
+}
+
+void ReposTab::refreshReposFailed(const ApiError& error)
+{
+ qDebug("failed to refresh repos");
+
+ if (mStack->currentIndex() == INDEX_LOADING_VIEW) {
+ mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+ }
+}
+
+std::vector<QAction*> ReposTab::getToolBarActions()
+{
+ return repos_tree_->getToolBarActions();
+}
+
+void ReposTab::showLoadingView()
+{
+ filter_text_->setVisible(false);
+ mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void ReposTab::refresh()
+{
+ if (!seafApplet->accountManager()->hasAccount() ||
+ !seafApplet->accountManager()->accounts().front().isValid()) {
+ mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+ return;
+ }
+ filter_text_->clear();
+ showLoadingView();
+ RepoService::instance()->refresh(true);
+}
+
+void ReposTab::startRefresh()
+{
+ RepoService::instance()->start();
+}
+
+void ReposTab::stopRefresh()
+{
+ RepoService::instance()->stop();
+}
+
+void ReposTab::onFilterTextChanged(const QString& text)
+{
+ repos_model_->onFilterTextChanged(text);
+ filter_model_->setFilterText(text.trimmed());
+ filter_model_->sort(0);
+ if (text.isEmpty()) {
+ repos_tree_->restoreExpandedCategries();
+ } else {
+ repos_tree_->expandAll();
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_REPOS_TAB_H
+#define SEAFILE_CLIENT_UI_REPOS_TAB_H
+
+#include <QLineEdit>
+
+#include "tab-view.h"
+
+class QTimer;
+class QToolButton;
+
+class RepoTreeModel;
+class RepoFilterProxyModel;
+class RepoTreeView;
+class ServerRepo;
+class ListReposRequest;
+class ApiError;
+class SearchBar;
+
+/**
+ * The repos list tab
+ */
+class ReposTab : public TabView {
+ Q_OBJECT
+public:
+ explicit ReposTab(QWidget *parent=0);
+
+ std::vector<QAction*> getToolBarActions();
+
+public slots:
+ void refresh();
+
+protected:
+ void startRefresh();
+ void stopRefresh();
+
+private slots:
+ void refreshRepos(const std::vector<ServerRepo>& repos);
+ void refreshReposFailed(const ApiError& error);
+ void onFilterTextChanged(const QString& text);
+
+private:
+ void createRepoTree();
+ void createLoadingView();
+ void createLoadingFailedView();
+ void showLoadingView();
+
+ RepoTreeModel *repos_model_;
+ RepoFilterProxyModel *filter_model_;
+
+ RepoTreeView *repos_tree_;
+ QWidget *loading_view_;
+ QWidget *loading_failed_view_;
+ QWidget *logout_view_;
+
+ SearchBar *filter_text_;
+
+ ListReposRequest *list_repo_req_;
+};
+
+#endif // SEAFILE_CLIENT_UI_REPOS_TAB_H
--- /dev/null
+#include <cstdio>
+#include <iostream>
+#include <QLabel>
+#include <QPaintEvent>
+#include <QStylePainter>
+#include <QStyleOptionTabV3>
+#include <QPixmap>
+#include <QIcon>
+#include <QStackedLayout>
+#include <QVBoxLayout>
+
+#include "utils/paint-utils.h"
+
+#include "seafile-tab-widget.h"
+
+namespace {
+
+const int kTabIconSize = 24;
+
+const char *kTabsBackgroundColor = "white";
+const char *kSelectedTabBorderBottomColor = "#D58747";
+const char *kBorderColor = "#DCDCDE";
+const int kSelectedTabBorderBottomWidth = 3;
+const int kSelectedTabBorderBottomHeightAlpha = 2;
+const int kSelectedTabBorderBottomWidthAlpha = 20;
+
+} // namespace
+
+SeafileTabBar::SeafileTabBar(QWidget *parent)
+ : QTabBar(parent)
+{
+ setMinimumSize(0, 48);
+}
+
+void SeafileTabBar::addTab(const QString& text,
+ const QString& icon_path,
+ const QString& highlighted_icon)
+{
+ int index = QTabBar::addTab(text);
+ setTabToolTip(index, text);
+ icons_.push_back(icon_path);
+ highlighted_icons_.push_back(highlighted_icon);
+}
+
+void SeafileTabBar::paintEvent(QPaintEvent *event)
+{
+ QStylePainter p(this);
+ QPainter painter;
+ painter.begin(this);
+
+ for (int index = 0, total = count(); index < total; index++) {
+ QRect rect = tabRect(index);
+ rect.adjust(0, 0, 0, 12);
+
+ // QStyleOptionTabV3 tab;
+ // initStyleOption(&tab, index);
+
+ // Draw the tab background
+ painter.fillRect(rect, QColor(kTabsBackgroundColor));
+
+ // Draw the tab icon in the center
+ QPoint top_left;
+ top_left.setX(rect.topLeft().x() + ((rect.width() - kTabIconSize) / 2));
+ top_left.setY(rect.topLeft().y() + ((rect.height() - kTabIconSize) / 2) + 2);
+
+ QIcon icon(currentIndex() == index ? highlighted_icons_[index]
+ : icons_[index]);
+ QRect icon_rect(top_left, QSize(kTabIconSize, kTabIconSize));
+ QPixmap icon_pixmap(icon.pixmap(QSize(kTabIconSize, kTabIconSize)));
+ painter.drawPixmap(icon_rect, icon_pixmap);
+
+ // int indicator_width = count() * rect.width() / 8;
+
+ // Draw the selected tab indicator
+ if (currentIndex() == index) {
+ // top_left.setX(rect.bottomLeft().x() + (rect.width() / 2) - (indicator_width / 2));
+ top_left.setX(rect.bottomLeft().x() + (rect.width() / 2) -
+ (kSelectedTabBorderBottomWidthAlpha / 2));
+ // top_left.setY(rect.bottomLeft().y() - kSelectedTabBorderBottomHeightAlpha + 1);
+ top_left.setY(rect.topLeft().y() + ((rect.height() - kTabIconSize) / 2) +
+ + 2 + kTabIconSize + 4);
+ QRect border_bottom_rect(top_left, QSize(kSelectedTabBorderBottomWidthAlpha,
+ kSelectedTabBorderBottomHeightAlpha));
+ painter.fillRect(border_bottom_rect, QColor(kSelectedTabBorderBottomColor));
+ }
+ }
+
+ // draw border
+ QPen borderPen(QColor(kBorderColor), 1);
+ painter.save();
+ painter.setPen(borderPen);
+ painter.drawLine(rect().topLeft(), rect().topRight());
+ painter.restore();
+}
+
+
+SeafileTabWidget::SeafileTabWidget(QWidget *parent)
+ : QWidget(parent)
+{
+ layout_ = new QVBoxLayout;
+ layout_->setContentsMargins(0, 0, 0, 0);
+ layout_->setSpacing(0);
+ setLayout(layout_);
+
+ tabbar_ = new SeafileTabBar;
+ tabbar_->setExpanding(true);
+
+ // Init content pane
+ pane_ = new QWidget;
+ // for qss style
+ pane_->setObjectName("pane");
+ stack_ = new QStackedLayout;
+ stack_->setContentsMargins(0, 0, 0, 0);
+ pane_->setLayout(stack_);
+
+ layout_->addWidget(tabbar_);
+ // layout_->addLayout(stack_);
+ layout_->addWidget(pane_);
+
+ connect(tabbar_, SIGNAL(currentChanged(int)),
+ stack_, SLOT(setCurrentIndex(int)));
+
+ connect(tabbar_, SIGNAL(currentChanged(int)),
+ this, SIGNAL(currentTabChanged(int)));
+}
+
+void SeafileTabWidget::addTab(QWidget* tab,
+ const QString& text,
+ const QString& icon_path,
+ const QString& highlighted_icon)
+{
+ tabbar_->addTab(text, icon_path, highlighted_icon);
+ stack_->addWidget(tab);
+}
+
+int SeafileTabWidget::currentIndex() const
+{
+ return stack_->currentIndex();
+}
+
+void SeafileTabWidget::adjustTabsWidth(int full_width)
+{
+ int tab_width = (full_width / tabbar_->count()) - 1;
+ QString style("QTabBar::tab { min-width: %1px; }");
+ style = style.arg(tab_width);
+ setStyleSheet(style);
+}
+
+void SeafileTabWidget::removeTab(int index, QWidget *widget)
+{
+ tabbar_->removeTab(index);
+ stack_->removeWidget(widget);
+}
+
+int SeafileTabWidget::count() const
+{
+ return tabbar_->count();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_SEAFILE_TAB_BAR_H
+#define SEAFILE_CLIENT_UI_SEAFILE_TAB_BAR_H
+
+#include <QTabBar>
+#include <vector>
+
+class QPaintEvent;
+class QVBoxLayout;
+class QStackedLayout;
+
+/**
+ * Custom tabbar used in the custom tab widget
+ */
+class SeafileTabBar : public QTabBar
+{
+ Q_OBJECT
+public:
+ SeafileTabBar(QWidget* parent = 0);
+
+ void paintEvent(QPaintEvent* event);
+
+ void addTab(const QString& text,
+ const QString& icon_path,
+ const QString& highlighted_icon);
+
+private:
+ std::vector<QString> icons_;
+ std::vector<QString> highlighted_icons_;
+};
+
+/**
+ * Custom tab widget, allow the tabbar to expand fully
+ */
+class SeafileTabWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ SeafileTabWidget(QWidget* parent = 0);
+
+ void addTab(QWidget* tab,
+ const QString& text,
+ const QString& icon_path,
+ const QString& highlighted_icon);
+
+ void removeTab(int index, QWidget* widget);
+
+ void adjustTabsWidth(int full_width);
+
+ int currentIndex() const;
+
+ int count() const;
+
+signals:
+ void currentTabChanged(int index);
+
+private:
+ QVBoxLayout* layout_;
+
+ SeafileTabBar* tabbar_;
+
+ QWidget* pane_;
+
+ QStackedLayout* stack_;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_SEAFILE_TAB_BAR_H
--- /dev/null
+#include <QToolButton>
+#include <QLabel>
+
+#include "search-bar.h"
+
+namespace {
+
+const int kMarginRightSearchBar = 16;
+const int kMarginBottom = 5;
+const int kHMargin = 10;
+
+} // namespace
+
+SearchBar::SearchBar(QWidget *parent)
+ : QLineEdit(parent)
+{
+ setObjectName("mSearchBar");
+
+ // This property was introduced in Qt 5.2.
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+ setClearButtonEnabled(false);
+#endif
+#ifdef Q_OS_MAC
+ setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+ placeholder_label_ = new QLabel(this);
+
+ clear_button_ = new QToolButton(this);
+ QIcon icon(":/images/cancel.png");
+ clear_button_size_ = 12;
+ clear_button_->setIcon(icon);
+ clear_button_->setIconSize(QSize(clear_button_size_, clear_button_size_));
+ clear_button_->setCursor(Qt::ArrowCursor);
+ clear_button_->setStyleSheet("QToolButton { border: 0px; }");
+ clear_button_->hide();
+ connect(clear_button_, SIGNAL(clicked()),
+ this, SLOT(clear()));
+
+ connect(this, SIGNAL(textChanged(const QString&)),
+ this, SLOT(onTextChanged(const QString&)));
+
+ const QString style = QString(" QLineEdit#mSearchBar { "
+ " padding-right: %1px; "
+ " padding-left: %2px; } " )
+ .arg(clear_button_size_ + kHMargin)
+ .arg(kHMargin);
+ setStyleSheet(style);
+}
+
+void SearchBar::paintEvent(QPaintEvent* event)
+{
+ QLineEdit::paintEvent(event);
+}
+
+void SearchBar::resizeEvent(QResizeEvent* event)
+{
+ clear_button_->move(rect().right() - kMarginRightSearchBar
+ - kHMargin - clear_button_size_ - 12,
+ (rect().bottom() - clear_button_size_) / 2);
+ int label_height = placeholder_label_->height();
+ int label_width = placeholder_label_->width();
+ placeholder_label_->move((rect().right() - label_width) / 2,
+ (rect().bottom() - label_height) / 2);
+}
+
+void SearchBar::onTextChanged(const QString& text)
+{
+ clear_button_->setVisible(!text.isEmpty());
+ placeholder_label_->setVisible(text.isEmpty());
+}
+
+void SearchBar::setPlaceholderText(const QString& text)
+{
+ placeholder_label_->setText(text);
+ placeholder_label_->setStyleSheet("QLabel { font-size: 13px;"
+ " color: #AAAAAA; }");
+ placeholder_label_->show();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SEARCH_BAR_H_
+#define SEAFILE_CLIENT_SEARCH_BAR_H_
+
+#include <QWidget>
+#include <QLineEdit>
+
+class QToolButton;
+class QLabel;
+
+class SearchBar : public QLineEdit
+{
+ Q_OBJECT
+public:
+ SearchBar(QWidget *parent=0);
+ void setPlaceholderText(const QString& text);
+
+private slots:
+ void onTextChanged(const QString& text);
+
+private:
+ Q_DISABLE_COPY(SearchBar)
+
+ void paintEvent(QPaintEvent* event);
+ void resizeEvent(QResizeEvent* event);
+
+ int clear_button_size_;
+ QToolButton *clear_button_;
+ QLabel *placeholder_label_;
+};
+
+#endif // SEAFILE_CLIENT_SEARCH_BAR_H_
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "ui/search-tab.h"
+#include "ui/search-tab-items.h"
+#include "ui/main-window.h"
+#include "utils/utils.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "seafile-applet.h"
+#include "api/requests.h"
+#include "repo-service.h"
+
+namespace {
+const int kMarginLeft = 5;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 5;
+
+const int kFileIconHeight = 36;
+const int kFileIconWidth = 36;
+const int kFileNameWidth = 210;
+const int kFileNameHeight = 30;
+
+const int kSubtitleHeight = 16;
+
+const int kMarginBetweenFileIconAndName = 10;
+
+const char *kFileNameColor = "#3F3F3F";
+const char *kFileNameColorHighlighted = "#544D49";
+const char *kSubtitleColor = "#959595";
+const char *kSubtitleColorHighlighted = "#9D9B9A";
+const int kFileNameFontSize = 14;
+const int kSubtitleFontSize = 11;
+
+const char *kFileItemBackgroundColor = "white";
+const char *kFileItemBackgroundColorHighlighted = "#F9E0C7";
+
+const char *kItemBottomBorderColor = "#EEE";
+
+const int PLACE_HOLDER_TYPE = 999;
+
+static inline const QListWidgetItem *getItem(const QModelIndex &index)
+{
+ const SearchResultListModel *model = static_cast<const SearchResultListModel*>(index.model());
+ return model->item(index);
+}
+static inline FileSearchResult getSearchResult(const QModelIndex &index)
+{
+ const QListWidgetItem *item = getItem(index);
+ if (!item)
+ return FileSearchResult();
+ return item->data(Qt::UserRole).value<FileSearchResult>();
+}
+} // anonymous namespace
+
+void SearchResultItemDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+ const SearchResultListModel *model = static_cast<const SearchResultListModel*>(index.model());
+ const QListWidgetItem* item = getItem(index);
+ if (item && item->type() == PLACE_HOLDER_TYPE) {
+ // This is the place holder item for the "load more" button
+ return;
+ }
+ QBrush backBrush;
+ bool selected = false;
+ FileSearchResult file = getSearchResult(index);
+
+ if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+ backBrush = QColor(kFileItemBackgroundColorHighlighted);
+ selected = true;
+ } else {
+ backBrush = QColor(kFileItemBackgroundColor);
+ }
+
+ //
+ // draw item's background
+ //
+ painter->save();
+ painter->fillRect(option.rect, backBrush);
+ painter->restore();
+
+ QIcon icon = model->data(index, Qt::DecorationRole).value<QIcon>();
+ QPixmap pixmap(icon.pixmap(QSize(kFileIconWidth, kFileIconHeight)));
+ //
+ // paint file icon
+ //
+ QPoint file_icon_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+ file_icon_pos += option.rect.topLeft();
+ painter->save();
+ painter->drawPixmap(file_icon_pos, pixmap);
+ painter->restore();
+
+ // Calculate the file column by the delta of mainwindow's width
+ QString title = file.name;
+
+ const int file_name_width = kFileNameWidth
+ + seafApplet->mainWindow()->width() - seafApplet->mainWindow()->minimumWidth();
+ painter->save();
+ QPoint file_name_pos = file_icon_pos + QPoint(kFileIconWidth + kMarginBetweenFileIconAndName, -kPadding);
+ QRect file_name_rect(file_name_pos, QSize(file_name_width, kFileNameHeight));
+ painter->setPen(QColor(selected ? kFileNameColorHighlighted : kFileNameColor));
+ painter->setFont(changeFontSize(painter->font(), kFileNameFontSize));
+
+ painter->drawText(file_name_rect,
+ Qt::AlignLeft | Qt::AlignTop,
+ fitTextToWidth(title, option.font, file_name_width),
+ &file_name_rect);
+ painter->restore();
+
+ //
+ // Paint repo_name
+ //
+ int count_of_splash = file.fullpath.endsWith("/") ? 2 : 1;
+ QString subtitle = file.fullpath.mid(1, file.fullpath.size() - count_of_splash - file.name.size());
+ if (!subtitle.isEmpty())
+ subtitle = file.repo_name + "/" + subtitle.left(subtitle.size() - 1);
+ else
+ subtitle = file.repo_name;
+
+ painter->save();
+ QPoint file_desc_pos = file_name_rect.bottomLeft() + QPoint(0, kPadding / 2);
+ QRect file_desc_rect(file_desc_pos, QSize(file_name_width, kSubtitleHeight));
+ painter->setFont(changeFontSize(painter->font(), kSubtitleFontSize));
+ painter->setPen(QColor(selected ? kSubtitleColorHighlighted : kSubtitleColor));
+ painter->drawText(file_desc_rect,
+ Qt::AlignLeft | Qt::AlignTop,
+ fitTextToWidth(subtitle, option.font, file_name_width),
+ &file_desc_rect);
+ painter->restore();
+
+ //
+ // Paint file description
+ //
+ QString size, mtime;
+
+ size = readableFileSize(file.size);
+ mtime = translateCommitTime(file.last_modified);
+
+ QString extra_title = size + " " + mtime;
+
+ painter->save();
+ QPoint file_extra_pos = file_desc_rect.bottomLeft() + QPoint(0, kPadding / 2 + 2);
+ QRect file_extra_rect(file_extra_pos, QSize(file_name_width, kSubtitleHeight));
+ painter->setFont(changeFontSize(painter->font(), kSubtitleFontSize));
+ painter->setPen(QColor(selected ? kSubtitleColorHighlighted : kSubtitleColor));
+ painter->drawText(file_extra_rect,
+ Qt::AlignLeft | Qt::AlignTop,
+ fitTextToWidth(extra_title, option.font, file_name_width),
+ &file_extra_rect);
+ painter->restore();
+
+ //
+ // Draw the bottom border lines
+ //
+ painter->save();
+ painter->setPen(QPen(QColor(kItemBottomBorderColor), 1, Qt::SolidLine));
+ painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
+ painter->restore();
+}
+
+QSize SearchResultItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const {
+
+ const QListWidgetItem* item = getItem(index);
+ if (!item)
+ return QStyledItemDelegate::sizeHint(option, index);
+
+ return QSize(kMarginLeft + kFileIconWidth + kMarginBetweenFileIconAndName + kFileNameWidth + kMarginRight + kPadding * 2,
+ kFileIconHeight + kPadding * 3 + kMarginTop + kMarginBottom);
+}
+
+SearchResultListView::SearchResultListView(QWidget* parent) : QListView(parent)
+{
+#if defined(Q_OS_MAC)
+ setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+ createActions();
+}
+
+void SearchResultListView::createActions()
+{
+ open_parent_dir_action_ = new QAction(tr("&Show in folder"), this);
+ open_parent_dir_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+ open_parent_dir_action_->setIconVisibleInMenu(true);
+ open_parent_dir_action_->setStatusTip(tr("Show in folder"));
+ connect(open_parent_dir_action_,
+ SIGNAL(triggered()),
+ this,
+ SLOT(openParentDir()));
+}
+
+void SearchResultListView::contextMenuEvent(QContextMenuEvent* event)
+{
+ QPoint pos = event->pos();
+ QModelIndex index = indexAt(pos);
+ if (!index.isValid()) {
+ return;
+ }
+
+ const QListWidgetItem* item = getItem(index);
+ if (!item) {
+ return;
+ }
+
+ updateActions();
+ QMenu* menu = prepareContextMenu();
+ pos = viewport()->mapToGlobal(pos);
+ menu->exec(pos);
+}
+
+QMenu* SearchResultListView::prepareContextMenu()
+{
+ QMenu* menu = new QMenu(this);
+ menu->addAction(open_parent_dir_action_);
+ return menu;
+}
+
+void SearchResultListView::updateActions()
+{
+ QModelIndexList indexes = selectionModel()->selection().indexes();
+ if (indexes.size() != 0) {
+ FileSearchResult file = getSearchResult(indexes.at(0));
+ open_parent_dir_action_->setData(QVariant::fromValue(file));
+ open_parent_dir_action_->setEnabled(true);
+ } else {
+ open_parent_dir_action_->setEnabled(false);
+ }
+}
+
+void SearchResultListView::openParentDir()
+{
+ FileSearchResult result =
+ qvariant_cast<FileSearchResult>(open_parent_dir_action_->data());
+ RepoService::instance()->openFolder(result.repo_id,
+ ::getParentPath(result.fullpath));
+}
+
+SearchResultListModel::SearchResultListModel() : QAbstractListModel()
+{
+ has_more_ = false;
+}
+
+void SearchResultListModel::addItem(QListWidgetItem *item)
+{
+ items_.push_back(item);
+ emit dataChanged(index(items_.size() - 1), index(items_.size() - 1));
+}
+
+const QModelIndex SearchResultListModel::updateSearchResults(
+ const std::vector<QListWidgetItem *> &items,
+ bool is_loading_more,
+ bool has_more)
+{
+ int first_new_item = 0;
+
+ beginResetModel();
+ if (!is_loading_more) {
+ first_new_item = 0;
+ clear();
+ } else {
+ if (items_.size() > 0 && items_[items_.size() - 1]->type() == PLACE_HOLDER_TYPE) {
+ QListWidgetItem *old_place_holder = items_[items_.size() - 1];
+ items_.pop_back();
+ first_new_item = items_.size();
+
+ delete old_place_holder;
+ }
+ }
+
+ items_.insert(items_.end(), items.begin(), items.end());
+
+ // place holder for the "load more" button
+ QListWidgetItem *load_more_place_holder = new QListWidgetItem(nullptr, PLACE_HOLDER_TYPE);
+ items_.push_back(load_more_place_holder);
+
+ load_more_index_ = QModelIndex();
+ if (has_more) {
+ load_more_index_ = index(items_.size() - 1);
+ }
+
+ endResetModel();
+
+ if (first_new_item) {
+ return index(first_new_item);
+ }
+ return QModelIndex();
+}
+
+int SearchResultListModel::rowCount(const QModelIndex &index) const
+{
+ return items_.size();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_SEARCH_TAB_ITEMS_H
+#define SEAFILE_CLIENT_UI_SEARCH_TAB_ITEMS_H
+
+#include <vector>
+#include <QAbstractItemModel>
+#include <QListWidgetItem>
+#include <QListView>
+#include <QStyledItemDelegate>
+
+class QAction;
+class QMenu;
+
+class SearchResultListView : public QListView {
+ Q_OBJECT
+public:
+ SearchResultListView(QWidget *parent=0);
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *event);
+
+private slots:
+ void openParentDir();
+
+private:
+ void createActions();
+ void updateActions();
+ QMenu *prepareContextMenu();
+
+ QAction *open_parent_dir_action_;
+};
+
+class SearchResultListModel : public QAbstractListModel {
+ Q_OBJECT
+public:
+ SearchResultListModel();
+ ~SearchResultListModel()
+ {
+ clear();
+ }
+ int rowCount(const QModelIndex &index) const;
+ const QListWidgetItem* item(const QModelIndex& index) const
+ {
+ if (!index.isValid() || index.row() >= (int)items_.size())
+ return NULL;
+ return items_[index.row()];
+ }
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
+ {
+ if (!index.isValid() || index.row() >= (int)items_.size())
+ return QVariant();
+ return items_[index.row()]->data(role);
+ }
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) {
+ if (index.row() >= (int)items_.size())
+ return false;
+ if (items_[index.row()]->data(role) == value)
+ return true;
+ items_[index.row()]->setData(role, value);
+ emit dataChanged(index, index);
+ return true;
+ }
+ void clear()
+ {
+ for (unsigned i = 0 ; i < items_.size(); ++i) {
+ delete items_[i];
+ }
+ items_.clear();
+ }
+
+ void addItem(QListWidgetItem *item);
+ const QModelIndex updateSearchResults(const std::vector<QListWidgetItem *> &items, bool is_loading_more, bool has_more);
+
+ const QModelIndex loadMoreIndex() const { return load_more_index_; }
+
+private:
+ std::vector<QListWidgetItem*> items_;
+ bool has_more_;
+ QModelIndex load_more_index_;
+};
+
+class SearchResultItemDelegate : public QStyledItemDelegate {
+public:
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_SEARCH_TAB_ITEMS_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "api/requests.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "utils/file-utils.h"
+#include "utils/paint-utils.h"
+#include "ui/search-bar.h"
+
+#include "ui/search-tab.h"
+#include "ui/search-tab-items.h"
+
+namespace {
+const int kMinimumKeywordLength = 3;
+const int kInputDelayInterval = 300;
+const char *kLoadingFailedLabelName = "loadingFailedText";
+
+enum {
+ INDEX_WAITING_VIEW = 0,
+ INDEX_LOADING_VIEW,
+ INDEX_LOADING_FAILED_VIEW,
+ INDEX_LOGOUT_VIEW,
+ INDEX_SEARCH_VIEW,
+};
+
+} // anonymous namespace
+
+SearchTab::SearchTab(QWidget *parent)
+ : TabView(parent), last_modified_(0), request_(NULL), nth_page_(1)
+{
+ createSearchView();
+ createLoadingView();
+ createLoadingFailedView();
+
+ //createLogoutView
+ logout_view_ = new LogoutView;
+ static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+ mStack->insertWidget(INDEX_WAITING_VIEW, waiting_view_);
+ mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+ mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+ mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+ mStack->insertWidget(INDEX_SEARCH_VIEW, search_view_);
+
+ connect(line_edit_, SIGNAL(textChanged(const QString&)),
+ this, SLOT(doSearch(const QString&)));
+
+ connect(search_view_, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onDoubleClicked(const QModelIndex&)));
+
+ search_timer_ = new QTimer(this);
+ connect(search_timer_, SIGNAL(timeout()), this, SLOT(doRealSearch()));
+ search_timer_->start(kInputDelayInterval);
+}
+
+SearchTab::~SearchTab()
+{
+ stopRefresh();
+ delete search_model_;
+}
+
+void SearchTab::reset()
+{
+ stopRefresh();
+ line_edit_->setText("");
+ mStack->setCurrentIndex(INDEX_WAITING_VIEW);
+}
+
+void SearchTab::createSearchView()
+{
+ QVBoxLayout *layout = (QVBoxLayout*)this->layout();
+ line_edit_ = new SearchBar;
+ line_edit_->setPlaceholderText(tr("Search files"));
+ layout->insertWidget(0, line_edit_);
+
+ waiting_view_ = new QWidget;
+ waiting_view_->installEventFilter(this);
+
+ search_view_ = new SearchResultListView;
+ search_view_->setObjectName("searchResult");
+#ifdef Q_OS_MAC
+ search_view_->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+ search_model_ = new SearchResultListModel;
+ search_view_->setModel(search_model_);
+
+ search_delegate_ = new SearchResultItemDelegate;
+
+ delete search_view_->itemDelegate();
+ search_view_->setItemDelegate(search_delegate_);
+}
+
+void SearchTab::createLoadingView()
+{
+ loading_view_ = new LoadingView;
+ static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void SearchTab::createLoadingFailedView()
+{
+ loading_failed_view_ = new QWidget(this);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ loading_failed_view_->setLayout(layout);
+
+ loading_failed_text_ = new QLabel;
+ loading_failed_text_->setObjectName(kLoadingFailedLabelName);
+ loading_failed_text_->setAlignment(Qt::AlignCenter);
+ QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+ QString label_text = tr("Failed to search<br/>"
+ "Please %1").arg(link);
+ loading_failed_text_->setText(label_text);
+
+ connect(loading_failed_text_, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(refresh()));
+
+ layout->addWidget(loading_failed_text_);
+}
+
+void SearchTab::showLoadingView()
+{
+ mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+bool SearchTab::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == waiting_view_ && event->type() == QEvent::Paint) {
+ QPainter painter(waiting_view_);
+
+ QPaintEvent *ev = (QPaintEvent*)event;
+ const QSize size(72, 72);
+ const int x = ev->rect().width() / 2 - size.width() / 2;
+ const int y = ev->rect().height() / 2 - size.height() / 2;
+ QRect rect(QPoint(x, y), size);
+
+ // get the device pixel radio from current painter device
+ int scale_factor = 1;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ scale_factor = globalDevicePixelRatio();
+#endif // QT5
+
+ QPixmap image = QIcon(":/images/main-panel/search-background.png").pixmap(size);
+ painter.drawPixmap(rect, image);
+
+ return true;
+ };
+ return QObject::eventFilter(obj, event);
+}
+
+void SearchTab::refresh()
+{
+ if (!seafApplet->accountManager()->currentAccount().isValid()) {
+ mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+ return;
+ }
+ if (!line_edit_->text().isEmpty()) {
+ last_modified_ = 1;
+ doRealSearch();
+ }
+}
+
+void SearchTab::startRefresh()
+{
+ search_timer_->start();
+}
+
+void SearchTab::stopRefresh()
+{
+ search_timer_->stop();
+ if (request_) {
+ request_->deleteLater();
+ request_ = NULL;
+ }
+}
+
+void SearchTab::doSearch(const QString& keyword)
+{
+ // make it search utf-8 charcters
+ if (keyword.toUtf8().size() < kMinimumKeywordLength) {
+ mStack->setCurrentIndex(INDEX_WAITING_VIEW);
+ return;
+ }
+
+ // save for doRealSearch
+ last_modified_ = QDateTime::currentMSecsSinceEpoch();
+}
+
+void SearchTab::doRealSearch(bool load_more)
+{
+ if (!load_more) {
+ // not modified
+ if (last_modified_ == 0)
+ return;
+ // modified too fast
+ if (QDateTime::currentMSecsSinceEpoch() - last_modified_ <= kInputDelayInterval)
+ return;
+ }
+
+ const Account& account = seafApplet->accountManager()->currentAccount();
+
+ if (!account.isValid())
+ return;
+ if (request_) {
+ // request_->abort();
+ request_->deleteLater();
+ request_ = NULL;
+ }
+
+ if (!load_more) {
+ nth_page_ = 1;
+ mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+ } else {
+ nth_page_++;
+ }
+
+ request_ = new FileSearchRequest(account, line_edit_->text(), nth_page_);
+ connect(request_, SIGNAL(success(const std::vector<FileSearchResult>&, bool, bool)),
+ this, SLOT(onSearchSuccess(const std::vector<FileSearchResult>&, bool, bool)));
+ connect(request_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(onSearchFailed(const ApiError&)));
+
+ request_->send();
+
+ // reset
+ last_modified_ = 0;
+}
+
+void SearchTab::onSearchSuccess(const std::vector<FileSearchResult>& results,
+ bool is_loading_more,
+ bool has_more)
+{
+ std::vector<QListWidgetItem*> items;
+
+ for (unsigned i = 0; i < results.size(); ++i) {
+ QListWidgetItem *item = new QListWidgetItem(results[i].name);
+ if (results[i].fullpath.endsWith("/"))
+ item->setIcon(QIcon(getIconByFolder()));
+ else
+ item->setIcon(QIcon(getIconByFileName(results[i].name)));
+ item->setData(Qt::UserRole, QVariant::fromValue(results[i]));
+ items.push_back(item);
+ }
+
+ mStack->setCurrentIndex(INDEX_SEARCH_VIEW);
+
+ const QModelIndex first_new_item = search_model_->updateSearchResults(items, is_loading_more, has_more);
+ if (first_new_item.isValid()) {
+ search_view_->scrollTo(first_new_item);
+ }
+
+ if (has_more) {
+ load_more_btn_ = new LoadMoreButton;
+ connect(load_more_btn_, SIGNAL(clicked()),
+ this, SLOT(loadMoreSearchResults()));
+ search_view_->setIndexWidget(
+ search_model_->loadMoreIndex(), load_more_btn_);
+ }
+}
+
+void SearchTab::loadMoreSearchResults()
+{
+ doRealSearch(true);
+}
+
+void SearchTab::onSearchFailed(const ApiError& error)
+{
+ mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+}
+
+void SearchTab::onDoubleClicked(const QModelIndex& index)
+{
+ FileSearchResult result = search_model_->data(index, Qt::UserRole).value<FileSearchResult>();
+ if (result.name.isEmpty() || result.fullpath.isEmpty())
+ return;
+
+ RepoService::instance()->openLocalFile(result.repo_id, result.fullpath);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_SEARCH_TAB_H
+#define SEAFILE_CLIENT_UI_SEARCH_TAB_H
+#include "tab-view.h"
+
+class QWidget;
+class QLabel;
+class QListView;
+class SearchResultListView;
+class SearchResultListModel;
+class SearchResultItemDelegate;
+class QListWidget;
+class QListWidgetItem;
+class QLineEdit;
+class QTimer;
+class QModelIndex;
+class FileSearchRequest;
+struct FileSearchResult;
+class ApiError;
+class LoadMoreButton;
+class SearchBar;
+
+class SearchTab : public TabView {
+ Q_OBJECT
+public:
+ explicit SearchTab(QWidget *parent = 0);
+ ~SearchTab();
+ void reset();
+
+public slots:
+ void refresh();
+
+protected:
+ void startRefresh();
+ void stopRefresh();
+
+private slots:
+ void doSearch(const QString& keyword);
+ void doRealSearch(bool load_more = false);
+ void loadMoreSearchResults();
+
+ void onDoubleClicked(const QModelIndex& index);
+
+ void onSearchSuccess(const std::vector<FileSearchResult>& results,
+ bool is_loading_more,
+ bool has_more);
+ void onSearchFailed(const ApiError& error);
+
+private:
+ void createSearchView();
+ void createLoadingView();
+ void createLoadingFailedView();
+ void showLoadingView();
+
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private:
+ qint64 last_modified_;
+ QTimer *search_timer_;
+ FileSearchRequest *request_;
+
+ QWidget *waiting_view_;
+ QWidget *loading_view_;
+ QWidget *loading_failed_view_;
+ QWidget *logout_view_;
+
+ QLabel *loading_failed_text_;
+ LoadMoreButton *load_more_btn_;
+
+ SearchBar *line_edit_;
+
+ SearchResultItemDelegate *search_delegate_;
+ SearchResultListView *search_view_;
+ SearchResultListModel *search_model_;
+
+ int nth_page_;
+};
+#endif // SEAFILE_CLIENT_UI_SEARCH_TAB_HSEAF
--- /dev/null
+#include "server-status-service.h"
+#include "server-status-dialog.h"
+
+ServerStatusDialog::ServerStatusDialog(QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+
+#if defined(Q_OS_MAC)
+ layout()->setContentsMargins(8, 9, 9, 4);
+ layout()->setSpacing(5);
+#endif
+
+ setWindowTitle(tr("Servers connection status"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ refreshStatus();
+
+ connect(ServerStatusService::instance(), SIGNAL(serverStatusChanged()),
+ this, SLOT(refreshStatus()));
+}
+
+void ServerStatusDialog::refreshStatus()
+{
+ mList->clear();
+
+ foreach (const ServerStatus& status, ServerStatusService::instance()->statuses()) {
+ QListWidgetItem *item = new QListWidgetItem(mList);
+ item->setData(Qt::DisplayRole, status.url.host());
+
+ if (status.connected) {
+ item->setData(Qt::DecorationRole, QIcon(":/images/sync/done.png"));
+ item->setData(Qt::ToolTipRole, tr("connected"));
+ } else {
+ item->setData(Qt::DecorationRole, QIcon(":/images/remove-red.png"));
+ item->setData(Qt::ToolTipRole, tr("disconnected"));
+ }
+
+ mList->addItem(item);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SERVER_STATUS_DIALOG_H
+#define SEAFILE_CLIENT_SERVER_STATUS_DIALOG_H
+
+#include <QDialog>
+#include "ui_server-status-dialog.h"
+
+class ServerStatusDialog : public QDialog,
+ public Ui::ServerStatusDialog
+{
+ Q_OBJECT
+public:
+ ServerStatusDialog(QWidget *parent=0);
+
+private slots:
+ void refreshStatus();
+
+private:
+ Q_DISABLE_COPY(ServerStatusDialog)
+};
+
+#endif // SEAFILE_CLIENT_SERVER_STATUS_DIALOG_H
--- /dev/null
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/api-error.h"
+#include "api/requests.h"
+
+#include "set-repo-password-dialog.h"
+
+SetRepoPasswordDialog::SetRepoPasswordDialog(const ServerRepo& repo, QWidget *parent)
+ : QDialog(parent),
+ repo_(repo)
+{
+ setupUi(this);
+ setWindowTitle(tr("Please provide the library password"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ request_ = 0;
+
+ QString name = QString("<b>%1</b>").arg(repo.name);
+ mHintText->setText(tr("Provide the password for library %1").arg(name));
+
+ mErrorText->setText(QString());
+
+ connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+}
+
+void SetRepoPasswordDialog::onOkBtnClicked()
+{
+ mErrorText->setText(QString());
+
+ password_ = mPassword->text().trimmed();
+
+ if (password_.isEmpty()) {
+ QString msg = tr("Please enter the password");
+ seafApplet->warningBox(msg, this);
+ return;
+ }
+
+ disableInputs();
+
+ const Account& account = seafApplet->accountManager()->currentAccount();
+
+ if (request_) {
+ request_->deleteLater();
+ }
+
+ request_ = new SetRepoPasswordRequest(account, repo_.id, password_);
+ connect(request_, SIGNAL(success()),
+ this, SLOT(accept()));
+ connect(request_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(requestFailed(const ApiError&)));
+
+ request_->send();
+}
+
+void SetRepoPasswordDialog::requestFailed(const ApiError& error)
+{
+ QString msg;
+ if (error.httpErrorCode() == 400) {
+ msg = tr("Incorrect password");
+ } else {
+ msg = tr("Unknown error");
+ }
+
+ mErrorText->setText(msg);
+
+ enableInputs();
+}
+
+void SetRepoPasswordDialog::enableInputs()
+{
+ mOkBtn->setEnabled(true);
+ mCancelBtn->setEnabled(true);
+ mPassword->setEnabled(true);
+}
+
+void SetRepoPasswordDialog::disableInputs()
+{
+ mOkBtn->setEnabled(false);
+ mCancelBtn->setEnabled(false);
+ mPassword->setEnabled(false);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SET_REPO_PASSWORD_DIALOG_H
+#define SEAFILE_CLIENT_SET_REPO_PASSWORD_DIALOG_H
+
+#include <QDialog>
+#include <QString>
+#include "ui_set-repo-password-dialog.h"
+
+#include "api/server-repo.h"
+
+class Account;
+class ApiError;
+class SetRepoPasswordRequest;
+
+class SetRepoPasswordDialog : public QDialog,
+ public Ui::SetRepoPasswordDialog
+{
+ Q_OBJECT
+public:
+ SetRepoPasswordDialog(const ServerRepo& repo, QWidget *parent=0);
+ const QString& password() { return password_; }
+
+private slots:
+ void onOkBtnClicked();
+ void requestFailed(const ApiError& error);
+
+private:
+ Q_DISABLE_COPY(SetRepoPasswordDialog);
+
+ void enableInputs();
+ void disableInputs();
+
+ QString password_;
+ SetRepoPasswordRequest *request_;
+ ServerRepo repo_;
+};
+
+#endif // SEAFILE_CLIENT_SET_REPO_PASSWORD_DIALOG_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QDebug>
+#include <QSettings>
+
+#include "i18n.h"
+#include "account-mgr.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "settings-mgr.h"
+#include "api/requests.h"
+#include "settings-dialog.h"
+
+#ifdef HAVE_SPARKLE_SUPPORT
+#include "auto-update-service.h"
+#endif
+
+namespace {
+
+const char *kSettingsGroupForSettingsDialog = "SettingsDialog";
+
+} // namespace
+
+SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent)
+{
+ setupUi(this);
+ setWindowTitle(tr("Settings"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ mAutoStartCheckBox->setText(
+ tr("Auto start %1 after login").arg(getBrand()));
+
+ mHideDockIconCheckBox->setText(
+ tr("Hide %1 Icon from the dock").arg(getBrand()));
+
+ mTabWidget->setCurrentIndex(0);
+
+#ifdef HAVE_SPARKLE_SUPPORT
+ if (!AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+ mCheckLatestVersionBox->setVisible(false);
+ }
+#endif
+
+ mLanguageComboBox->addItems(I18NHelper::getInstance()->getLanguages());
+ // The range of mProxyPort is set to (0, 65535) in the ui file, so we
+ // don't bother with that here.
+ mProxyMethodComboBox->insertItem(SettingsManager::NoProxy, tr("None"));
+ mProxyMethodComboBox->insertItem(SettingsManager::HttpProxy, tr("HTTP Proxy"));
+ mProxyMethodComboBox->insertItem(SettingsManager::SocksProxy, tr("Socks5 Proxy"));
+ mProxyMethodComboBox->insertItem(SettingsManager::SystemProxy, tr("System Proxy"));
+ connect(mProxyMethodComboBox, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(showHideControlsBasedOnCurrentProxyType(int)));
+ connect(mProxyRequirePassword, SIGNAL(stateChanged(int)),
+ this, SLOT(proxyRequirePasswordChanged(int)));
+
+#if defined(Q_OS_MAC)
+ layout()->setContentsMargins(8, 9, 9, 4);
+ layout()->setSpacing(5);
+
+ mDownloadSpinBox->setAttribute(Qt::WA_MacShowFocusRect, 0);
+ mUploadSpinBox->setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+ connect(mOkBtn, SIGNAL(clicked()), this, SLOT(onOkBtnClicked()));
+}
+
+void SettingsDialog::updateSettings()
+{
+ SettingsManager *mgr = seafApplet->settingsManager();
+ mgr->setNotify(mNotifyCheckBox->checkState() == Qt::Checked);
+ mgr->setAutoStart(mAutoStartCheckBox->checkState() == Qt::Checked);
+ mgr->setHideDockIcon(mHideDockIconCheckBox->checkState() == Qt::Checked);
+ mgr->setSyncExtraTempFile(mSyncExtraTempFileCheckBox->checkState() == Qt::Checked);
+ mgr->setMaxDownloadRatio(mDownloadSpinBox->value());
+ mgr->setMaxUploadRatio(mUploadSpinBox->value());
+ mgr->setHideMainWindowWhenStarted(mHideMainWinCheckBox->checkState() == Qt::Checked);
+ mgr->setAllowInvalidWorktree(mAllowInvalidWorktreeCheckBox->checkState() == Qt::Checked);
+ mgr->setHttpSyncCertVerifyDisabled(mDisableVerifyHttpSyncCert->checkState() == Qt::Checked);
+ mgr->setAllowRepoNotFoundOnServer(mAllowRepoNotFoundCheckBox->checkState() == Qt::Checked);
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+ if(mFinderSyncCheckBox->isEnabled())
+ mgr->setFinderSyncExtension(mFinderSyncCheckBox->checkState() == Qt::Checked);
+#endif
+#ifdef Q_OS_WIN32
+ mgr->setShellExtensionEnabled(mShellExtCheckBox->checkState() == Qt::Checked);
+#endif
+
+ updateProxySettings();
+
+#ifdef HAVE_SPARKLE_SUPPORT
+ if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+ bool enabled = mCheckLatestVersionBox->checkState() == Qt::Checked;
+ AutoUpdateService::instance()->setAutoUpdateEnabled(enabled);
+ }
+#endif
+
+ bool language_changed = false;
+ if (mLanguageComboBox->currentIndex() != I18NHelper::getInstance()->preferredLanguage()) {
+ language_changed = true;
+ I18NHelper::getInstance()->setPreferredLanguage(mLanguageComboBox->currentIndex());
+ }
+
+ if (language_changed && seafApplet->yesOrNoBox(tr("You have changed languange. Restart to apply it?"), this, true))
+ seafApplet->restartApp();
+
+ // if (proxy_changed && seafApplet->yesOrNoBox(tr("You have changed proxy settings. Restart to apply it?"), this, true))
+ // seafApplet->restartApp();
+
+}
+
+void SettingsDialog::closeEvent(QCloseEvent *event)
+{
+ // There is only one instance of settings dialog during the applet life
+ // time. During startup, applet loads settings from registry (or similar
+ // places on linux/osx) and load part of the settings from seaf daemon.
+ // Each time a user modifieds a settings item and clicks "OK" button, the
+ // change is both updated in memory and persisted to the registry.
+ event->ignore();
+ hide();
+}
+
+void SettingsDialog::showEvent(QShowEvent *event)
+{
+ SettingsManager *mgr = seafApplet->settingsManager();
+ // mgr->loadSettings();
+
+ Qt::CheckState state;
+ state = mgr->hideMainWindowWhenStarted() ? Qt::Checked : Qt::Unchecked;
+ mHideMainWinCheckBox->setCheckState(state);
+
+ state = mgr->allowInvalidWorktree() ? Qt::Checked : Qt::Unchecked;
+ mAllowInvalidWorktreeCheckBox->setCheckState(state);
+
+ state = mgr->syncExtraTempFile() ? Qt::Checked : Qt::Unchecked;
+ mSyncExtraTempFileCheckBox->setCheckState(state);
+
+ state = mgr->allowRepoNotFoundOnServer() ? Qt::Checked : Qt::Unchecked;
+ mAllowRepoNotFoundCheckBox->setCheckState(state);
+
+ state = mgr->httpSyncCertVerifyDisabled() ? Qt::Checked : Qt::Unchecked;
+ mDisableVerifyHttpSyncCert->setCheckState(state);
+
+ // currently supports windows only
+ state = mgr->autoStart() ? Qt::Checked : Qt::Unchecked;
+ mAutoStartCheckBox->setCheckState(state);
+#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC)
+ mAutoStartCheckBox->hide();
+#endif
+#ifdef HAVE_FINDER_SYNC_SUPPORT
+ if (mgr->getFinderSyncExtensionAvailable()) {
+ mFinderSyncCheckBox->setEnabled(true);
+ state = mgr->getFinderSyncExtension() ? Qt::Checked : Qt::Unchecked;
+ mFinderSyncCheckBox->setCheckState(state);
+ } else {
+ mFinderSyncCheckBox->setEnabled(false);
+ }
+#else
+ mFinderSyncCheckBox->hide();
+#endif
+
+#if defined(Q_OS_WIN32)
+ state = mgr->shellExtensionEnabled() ? Qt::Checked : Qt::Unchecked;
+ mShellExtCheckBox->setCheckState(state);
+#else
+ mShellExtCheckBox->hide();
+#endif
+
+ // currently supports mac only
+ state = mgr->hideDockIcon() ? Qt::Checked : Qt::Unchecked;
+ mHideDockIconCheckBox->setCheckState(state);
+#if !defined(Q_OS_MAC)
+ mHideDockIconCheckBox->hide();
+#endif
+
+ state = mgr->notify() ? Qt::Checked : Qt::Unchecked;
+ mNotifyCheckBox->setCheckState(state);
+
+ int ratio;
+ ratio = mgr->maxDownloadRatio();
+ mDownloadSpinBox->setValue(ratio);
+ ratio = mgr->maxUploadRatio();
+ mUploadSpinBox->setValue(ratio);
+
+#ifdef HAVE_SPARKLE_SUPPORT
+ if (AutoUpdateService::instance()->shouldSupportAutoUpdate()) {
+ state = AutoUpdateService::instance()->autoUpdateEnabled() ? Qt::Checked : Qt::Unchecked;
+ mCheckLatestVersionBox->setCheckState(state);
+ }
+#endif
+
+ mEnableSyncingWithExistingFolder->hide();
+
+ SettingsManager::SeafileProxy proxy = mgr->getProxy();
+ showHideControlsBasedOnCurrentProxyType(proxy.type);
+ mProxyMethodComboBox->setCurrentIndex(proxy.type);
+ mProxyHost->setText(proxy.host);
+ mProxyPort->setValue(proxy.port);
+ mProxyUsername->setText(proxy.username);
+ mProxyPassword->setText(proxy.password);
+ if (!proxy.username.isEmpty())
+ mProxyRequirePassword->setChecked(true);
+
+ mLanguageComboBox->setCurrentIndex(I18NHelper::getInstance()->preferredLanguage());
+
+ QDialog::showEvent(event);
+}
+
+
+void SettingsDialog::autoStartChanged(int state)
+{
+ qDebug("%s :%d", __func__, state);
+ bool autoStart = (mAutoStartCheckBox->checkState() == Qt::Checked);
+ seafApplet->settingsManager()->setAutoStart(autoStart);
+}
+
+void SettingsDialog::hideDockIconChanged(int state)
+{
+ qDebug("%s :%d", __func__, state);
+ bool hideDockIcon = (mHideDockIconCheckBox->checkState() == Qt::Checked);
+ seafApplet->settingsManager()->setHideDockIcon(hideDockIcon);
+}
+
+void SettingsDialog::notifyChanged(int state)
+{
+ qDebug("%s :%d", __func__, state);
+ bool notify = (mNotifyCheckBox->checkState() == Qt::Checked);
+ seafApplet->settingsManager()->setNotify(notify);
+}
+
+void SettingsDialog::downloadChanged(int value)
+{
+ qDebug("%s :%d", __func__, value);
+ seafApplet->settingsManager()->setMaxDownloadRatio(mDownloadSpinBox->value());
+}
+
+void SettingsDialog::uploadChanged(int value)
+{
+ qDebug("%s :%d", __func__, value);
+ seafApplet->settingsManager()->setMaxUploadRatio(mUploadSpinBox->value());
+}
+
+void SettingsDialog::proxyRequirePasswordChanged(int state)
+{
+ if (state == Qt::Checked) {
+ mProxyUsername->setEnabled(true);
+ mProxyUsernameLabel->setEnabled(true);
+ mProxyPassword->setEnabled(true);
+ mProxyPasswordLabel->setEnabled(true);
+ } else {
+ mProxyUsername->setEnabled(false);
+ mProxyUsernameLabel->setEnabled(false);
+ mProxyPassword->setEnabled(false);
+ mProxyPasswordLabel->setEnabled(false);
+ }
+}
+
+void SettingsDialog::showHideControlsBasedOnCurrentProxyType(int state)
+{
+ SettingsManager::ProxyType proxy_type =
+ static_cast<SettingsManager::ProxyType>(state);
+ switch(proxy_type) {
+ case SettingsManager::HttpProxy:
+ mProxyHost->setVisible(true);
+ mProxyHostLabel->setVisible(true);
+ mProxyPort->setVisible(true);
+ mProxyPortLabel->setVisible(true);
+ mProxyRequirePassword->setVisible(true);
+ mProxyUsername->setVisible(true);
+ mProxyUsernameLabel->setVisible(true);
+ mProxyPassword->setVisible(true);
+ mProxyPasswordLabel->setVisible(true);
+ break;
+ case SettingsManager::SocksProxy:
+ mProxyHost->setVisible(true);
+ mProxyHostLabel->setVisible(true);
+ mProxyPort->setVisible(true);
+ mProxyPortLabel->setVisible(true);
+ mProxyRequirePassword->setVisible(false);
+ mProxyUsername->setVisible(false);
+ mProxyUsernameLabel->setVisible(false);
+ mProxyPassword->setVisible(false);
+ mProxyPasswordLabel->setVisible(false);
+ break;
+ case SettingsManager::NoProxy:
+ case SettingsManager::SystemProxy:
+ default:
+ mProxyHost->setVisible(false);
+ mProxyHostLabel->setVisible(false);
+ mProxyPort->setVisible(false);
+ mProxyPortLabel->setVisible(false);
+ mProxyRequirePassword->setVisible(false);
+ mProxyUsername->setVisible(false);
+ mProxyUsernameLabel->setVisible(false);
+ mProxyPassword->setVisible(false);
+ mProxyPasswordLabel->setVisible(false);
+ break;
+ }
+
+ if (proxy_type == SettingsManager::HttpProxy ||
+ proxy_type == SettingsManager::SocksProxy) {
+ QString prefix =
+ proxy_type == SettingsManager::HttpProxy ? "http" : "socks";
+ QSettings settings;
+ QString key;
+ settings.beginGroup(kSettingsGroupForSettingsDialog);
+ if (mProxyHost->text().trimmed().isEmpty()) {
+ key = prefix + "_proxy_host";
+ if (settings.contains(key)) {
+ mProxyHost->setText(settings.value(key).toString());
+ }
+ }
+ if (mProxyPort->value() == 0) {
+ key = prefix + "_proxy_port";
+ if (settings.contains(key)) {
+ mProxyPort->setValue(settings.value(key).toInt());
+ }
+ }
+ }
+}
+
+// Called when the user clicked "OK" button of the settings dialog. Return
+// true if the proxy settings has been changed by the user.
+bool SettingsDialog::updateProxySettings()
+{
+ SettingsManager *mgr = seafApplet->settingsManager();
+ SettingsManager::SeafileProxy old_proxy = mgr->getProxy();
+
+ SettingsManager::ProxyType proxy_type = static_cast<SettingsManager::ProxyType>(mProxyMethodComboBox->currentIndex());
+ QString proxy_host = mProxyHost->text().trimmed();
+ QString proxy_username = mProxyUsername->text().trimmed();
+ QString proxy_password = mProxyPassword->text().trimmed();
+ int proxy_port = mProxyPort->value();
+
+ SettingsManager::SeafileProxy new_proxy(proxy_type);
+
+ switch(proxy_type) {
+ case SettingsManager::HttpProxy:
+ new_proxy.host = proxy_host;
+ new_proxy.port = proxy_port;
+ if (mProxyRequirePassword->checkState() == Qt::Checked) {
+ new_proxy.username = proxy_username;
+ new_proxy.password = proxy_password;
+ break;
+ }
+ break;
+ case SettingsManager::SocksProxy:
+ new_proxy.host = proxy_host;
+ new_proxy.port = proxy_port;
+ break;
+ case SettingsManager::NoProxy:
+ case SettingsManager::SystemProxy:
+ default:
+ break;
+ }
+
+ if (new_proxy != old_proxy) {
+ mgr->setProxy(new_proxy);
+ return true;
+ }
+
+ return false;
+}
+
+bool SettingsDialog::validateProxyInputs()
+{
+ SettingsManager::ProxyType proxy_type =
+ static_cast<SettingsManager::ProxyType>(
+ mProxyMethodComboBox->currentIndex());
+ if (proxy_type == SettingsManager::NoProxy ||
+ proxy_type == SettingsManager::SystemProxy) {
+ return true;
+ }
+
+ QString proxy_host = mProxyHost->text().trimmed();
+ if (proxy_host.isEmpty()) {
+ seafApplet->warningBox(tr("The proxy host address can't be empty"),
+ this);
+ return false;
+ }
+
+ int proxy_port = mProxyPort->value();
+ if (proxy_port == 0) {
+ seafApplet->warningBox(tr("The proxy port is incorrect"),
+ this);
+ return false;
+ }
+
+ if (mProxyRequirePassword->checkState() == Qt::Checked) {
+ QString proxy_username = mProxyUsername->text().trimmed();
+ QString proxy_password = mProxyPassword->text().trimmed();
+ if (proxy_username.isEmpty()) {
+ seafApplet->warningBox(tr("Proxy username can't be empty"), this);
+ return false;
+ } else if (proxy_password.isEmpty()) {
+ seafApplet->warningBox(tr("Proxy password can't be empty"), this);
+ return false;
+ }
+ }
+
+ QSettings settings;
+
+ settings.beginGroup(kSettingsGroupForSettingsDialog);
+ if (proxy_type == SettingsManager::HttpProxy) {
+ settings.setValue("http_proxy_host", proxy_host);
+ settings.setValue("http_proxy_port", proxy_port);
+ } else if (proxy_type == SettingsManager::SocksProxy) {
+ settings.setValue("socks_proxy_host", proxy_host);
+ settings.setValue("socks_proxy_port", proxy_port);
+ }
+ settings.endGroup();
+
+ return true;
+}
+
+void SettingsDialog::onOkBtnClicked()
+{
+ if (!validateProxyInputs()) {
+ return;
+ }
+ updateSettings();
+ accept();
+}
--- /dev/null
+#include <QDialog>
+#include "ui_settings-dialog.h"
+
+#include <QUrl>
+#include <QString>
+
+
+class SettingsDialog : public QDialog,
+ public Ui::SettingsDialog
+{
+ Q_OBJECT
+public:
+ SettingsDialog(QWidget *parent=0);
+
+private slots:
+
+ void autoStartChanged(int state);
+ void hideDockIconChanged(int state);
+ void notifyChanged(int state);
+ void downloadChanged(int value);
+ void uploadChanged(int value);
+ void closeEvent(QCloseEvent *event);
+ void showEvent(QShowEvent *event);
+ void updateSettings();
+ void onOkBtnClicked();
+
+ void proxyRequirePasswordChanged(int state);
+ void showHideControlsBasedOnCurrentProxyType(int state);
+
+private:
+ bool updateProxySettings();
+ bool validateProxyInputs();
+
+ Q_DISABLE_COPY(SettingsDialog);
+};
--- /dev/null
+#include "seafile-applet.h"
+#include "ssl-confirm-dialog.h"
+
+#include "utils/utils.h"
+
+SslConfirmDialog::SslConfirmDialog(const QUrl& url,
+ const QSslCertificate& cert,
+ const QSslCertificate& prev_cert,
+ QWidget *parent)
+ : QDialog(parent),
+ url_(url)
+{
+ setupUi(this);
+
+ setWindowTitle(tr("Untrusted Connection"));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ QString hint = tr("%1 uses an invalid security certificate. The connection may be insecure. Do you want to continue?").arg(url_.host());
+
+ QString fingerprint = dumpCertificateFingerprint(cert);
+ QString prev_fingerprint = dumpCertificateFingerprint(prev_cert);
+
+ hint += "\n\n";
+ hint += tr("Current RSA key fingerprint is %1").arg(fingerprint);
+ if (prev_fingerprint != "") {
+ hint += "\n";
+ hint += tr("Previous RSA key fingerprint is %1").arg(prev_fingerprint);
+ }
+
+ mHint->setText(hint);
+
+ adjustSize();
+
+ connect(mYesBtn, SIGNAL(clicked()), this, SLOT(accept()));
+ connect(mNoBtn, SIGNAL(clicked()), this, SLOT(reject()));
+}
+
+bool
+SslConfirmDialog::rememberChoice() const
+{
+ return mRememberChoiceCheckBox->checkState() == Qt::Checked;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_SSL_CONFIRM_DIALOG_H
+#define SEAFILE_CLIENT_UI_SSL_CONFIRM_DIALOG_H
+
+#include <QUrl>
+
+#include <QDialog>
+#include "ui_ssl-confirm-dialog.h"
+
+class QSslCertificate;
+
+class SslConfirmDialog : public QDialog,
+ public Ui::SslConfirmDialog
+{
+ Q_OBJECT
+public:
+ SslConfirmDialog(const QUrl& url,
+ const QSslCertificate& cert,
+ const QSslCertificate& prev_cert,
+ QWidget *parent=0);
+
+ bool rememberChoice() const;
+
+private:
+ QUrl url_;
+};
+
+
+#endif // SEAFILE_CLIENT_UI_SSL_CONFIRM_DIALOG_H
--- /dev/null
+#include <QPainter>
+#include <QApplication>
+#include <QPixmap>
+
+#include "utils/utils.h"
+#include "utils/paint-utils.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "main-window.h"
+#include "rpc/rpc-client.h"
+#include "starred-files-list-model.h"
+#include "starred-file-item.h"
+#include "api/server-repo.h"
+
+#include "starred-file-item-delegate.h"
+
+namespace {
+
+/**
+ name
+ icon
+ subtitle
+ */
+
+const int kMarginLeft = 5;
+const int kMarginRight = 5;
+const int kMarginTop = 5;
+const int kMarginBottom = 5;
+const int kPadding = 5;
+
+const int kFileIconHeight = 36;
+const int kFileIconWidth = 36;
+const int kFileNameWidth = 210;
+const int kFileNameHeight = 30;
+
+const int kMarginBetweenFileIconAndName = 10;
+
+const char *kFileNameColor = "#3F3F3F";
+const char *kFileNameColorHighlighted = "#544D49";
+const char *kSubtitleColor = "#959595";
+const char *kSubtitleColorHighlighted = "#9D9B9A";
+const int kFileNameFontSize = 14;
+const int kSubtitleFontSize = 13;
+
+const char *kFileItemBackgroundColor = "white";
+const char *kFileItemBackgroundColorHighlighted = "#F9E0C7";
+
+const char *kItemBottomBorderColor = "#EEE";
+
+} // namespace
+
+StarredFileItemDelegate::StarredFileItemDelegate(QObject *parent)
+ : QStyledItemDelegate(parent)
+{
+}
+
+QSize StarredFileItemDelegate::sizeHint(const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ StarredFileItem *item = getItem(index);
+ if (!item) {
+ return QStyledItemDelegate::sizeHint(option, index);
+ }
+
+ return sizeHintForItem(option, item);
+}
+
+QSize StarredFileItemDelegate::sizeHintForItem(const QStyleOptionViewItem &option,
+ const StarredFileItem *item) const
+{
+ static const int width = kMarginLeft + kFileIconWidth
+ + kMarginBetweenFileIconAndName + kFileNameWidth
+ + kMarginRight + kPadding * 2;
+
+ static const int height = kFileIconHeight + kPadding * 2 + kMarginTop + kMarginBottom;
+
+ return QSize(width, height);
+}
+
+void StarredFileItemDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ StarredFileItem *item = getItem(index);
+
+ paintItem(painter, option, item);
+}
+
+void StarredFileItemDelegate::paintItem(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const StarredFileItem *item) const
+{
+ QBrush backBrush;
+ bool selected = false;
+ const StarredItem& file = item->file();
+
+ if (option.state & (QStyle::State_HasFocus | QStyle::State_Selected)) {
+ backBrush = QColor(kFileItemBackgroundColorHighlighted);
+ selected = true;
+
+ } else {
+ backBrush = QColor(kFileItemBackgroundColor);
+ }
+
+ painter->save();
+ painter->fillRect(option.rect, backBrush);
+ painter->restore();
+
+ // paint file icon
+ QPixmap icon;
+ switch (file.type) {
+ case StarredItem::REPO:
+ icon = QIcon(":/images/library-256.png").pixmap(36);
+ break;
+ case StarredItem::DIR:
+ icon = QIcon(":/images/files/file_folder.png").pixmap(36);
+ break;
+ default: // server version lower 7.0.0 will execute the statement
+ icon = getIconForFile(file.name());
+ break;
+ }
+
+ QPoint file_icon_pos(kMarginLeft + kPadding, kMarginTop + kPadding);
+ file_icon_pos += option.rect.topLeft();
+ painter->save();
+ painter->drawPixmap(file_icon_pos, icon);
+ painter->restore();
+
+ // Calculate the file column by the delta of mainwindow's width
+ const int file_name_width = kFileNameWidth
+ + seafApplet->mainWindow()->width() - seafApplet->mainWindow()->minimumWidth();
+
+ // Paint file name
+ painter->save();
+ QPoint file_name_pos = file_icon_pos + QPoint(kFileIconWidth + kMarginBetweenFileIconAndName, 0);
+ QRect file_name_rect(file_name_pos, QSize(file_name_width, kFileNameHeight));
+ painter->setPen(QColor(selected ? kFileNameColorHighlighted : kFileNameColor));
+ painter->setFont(changeFontSize(painter->font(), kFileNameFontSize));
+
+ painter->drawText(file_name_rect,
+ Qt::AlignLeft | Qt::AlignTop,
+ fitTextToWidth(file.name(), option.font, file_name_width),
+ &file_name_rect);
+ painter->restore();
+
+ // Paint subtitle
+ QString subtitle, size, mtime;
+
+ size = readableFileSize(file.size);
+ mtime = translateCommitTime(file.mtime);
+
+ if (file.from_new_api) {
+ subtitle = mtime;
+ } else {
+ subtitle = size + " " + mtime;
+ }
+
+ painter->save();
+ QPoint file_desc_pos = file_name_rect.bottomLeft() + QPoint(0, 5);
+ QRect file_desc_rect(file_desc_pos, QSize(file_name_width, kFileNameHeight));
+ painter->setFont(changeFontSize(painter->font(), kSubtitleFontSize));
+ painter->setPen(QColor(selected ? kSubtitleColorHighlighted : kSubtitleColor));
+ painter->drawText(file_desc_rect,
+ Qt::AlignLeft | Qt::AlignTop,
+ fitTextToWidth(subtitle, option.font, file_name_width),
+ &file_desc_rect);
+ painter->restore();
+
+ // Draw the bottom border lines
+ painter->save();
+ painter->setPen(QPen(QColor(kItemBottomBorderColor), 1, Qt::SolidLine));
+ painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
+ painter->restore();
+}
+
+QPixmap StarredFileItemDelegate::getIconForFile(const QString& name) const
+{
+ return QIcon(::getIconByFileName(name)).pixmap(QSize(kFileIconWidth, kFileIconHeight));
+}
+
+StarredFileItem* StarredFileItemDelegate::getItem(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return NULL;
+ }
+
+ const StarredFilesListModel *model = (const StarredFilesListModel*)index.model();
+
+ return (StarredFileItem *)(model->itemFromIndex(index));
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+#define SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
+
+#include <QStyledItemDelegate>
+#include <QPixmap>
+
+class QStandardItem;
+class QModelIndex;
+class QWidget;
+
+class StarredFileItem;
+
+class StarredFileItemDelegate : public QStyledItemDelegate {
+ Q_OBJECT
+public:
+ explicit StarredFileItemDelegate(QObject *parent=0);
+
+ void paint(QPainter *painter,
+ const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+ QSize sizeHint(const QStyleOptionViewItem& option,
+ const QModelIndex& index) const;
+
+
+private:
+ void paintItem(QPainter *painter,
+ const QStyleOptionViewItem& opt,
+ const StarredFileItem *item) const;
+
+ QSize sizeHintForItem(const QStyleOptionViewItem &option,
+ const StarredFileItem *item) const;
+
+ StarredFileItem* getItem(const QModelIndex &index) const;
+
+ QPixmap getIconForFile(const QString& name) const;
+};
+
+
+#endif // SEAFILE_CLIENT_REPO_ITEM_DELEGATE_H
--- /dev/null
+
+#include "starred-file-item.h"
+
+StarredFileItem::StarredFileItem(const StarredItem& file)
+ : file_(file)
+{
+ setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_STARRED_FILE_ITEM_H
+#define SEAFILE_CLIENT_STARRED_FILE_ITEM_H
+
+#include <QStandardItem>
+#include "api/starred-file.h"
+
+/**
+ * Represent a repo
+ */
+class StarredFileItem : public QStandardItem {
+public:
+ explicit StarredFileItem(const StarredItem& repo);
+
+ const StarredItem& file() const { return file_; }
+
+ /**
+ * Every time the item is painted, we record the metrics of each part of
+ * the item on the screen. So later we the mouse click/hover the item, we
+ * can decide which part is hovered, and to do corresponding actions.
+ */
+ struct Metrics {
+ QRect icon_rect;
+ QRect name_rect;
+ QRect subtitle_rect;
+ QRect status_icon_rect;
+ };
+
+ void setMetrics(const Metrics& metrics) const { metrics_ = metrics; }
+ const Metrics& metrics() const { return metrics_; }
+
+private:
+ StarredItem file_;
+
+ mutable Metrics metrics_;
+};
+
+#endif // SEAFILE_CLIENT_STARRED_FILE_ITEM_H
--- /dev/null
+#include <QTimer>
+#include <QHash>
+#include <QDebug>
+#include <algorithm> // std::sort
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "main-window.h"
+#include "rpc/rpc-client.h"
+#include "starred-file-item.h"
+
+#include "starred-files-list-model.h"
+
+namespace {
+
+bool compareFileByTimestamp(const StarredItem& a, const StarredItem& b)
+{
+ return a.mtime > b.mtime;
+}
+
+} // namespace
+
+StarredFilesListModel::StarredFilesListModel(QObject *parent)
+ : QStandardItemModel(parent)
+{
+}
+
+void StarredFilesListModel::setFiles(const std::vector<StarredItem>& files)
+{
+ int i, n = files.size();
+
+ clear();
+
+ std::vector<StarredItem> list = files;
+
+ std::sort(list.begin(), list.end(), compareFileByTimestamp);
+
+ for (i = 0; i < n; i++) {
+ StarredFileItem *item = new StarredFileItem(files[i]);
+ appendRow(item);
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_STARRED_FILES_LIST_MODEL_H
+#define SEAFILE_CLIENT_STARRED_FILES_LIST_MODEL_H
+
+#include <vector>
+#include <QStandardItemModel>
+
+#include "api/starred-file.h"
+
+class QModelIndex;
+
+
+class StarredFilesListModel : public QStandardItemModel {
+ Q_OBJECT
+
+public:
+ StarredFilesListModel(QObject *parent=0);
+
+ void setFiles(const std::vector<StarredItem>& files);
+
+private:
+
+ std::vector<StarredItem> files_;
+};
+
+#endif // SEAFILE_CLIENT_STARRED_FILES_LIST_MODEL_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#include <QUrlQuery>
+#else
+#include <QtGui>
+#endif
+#include <QHeaderView>
+#include <QDesktopServices>
+#include <QEvent>
+#include <QShowEvent>
+#include <QHideEvent>
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "repo-service.h"
+#include "starred-file-item.h"
+#include "starred-files-list-model.h"
+
+#include "starred-files-list-view.h"
+
+
+StarredFilesListView::StarredFilesListView(QWidget *parent)
+ : QListView(parent)
+{
+#if defined(Q_OS_MAC)
+ setAttribute(Qt::WA_MacShowFocusRect, 0);
+#endif
+
+ createActions();
+
+ connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+}
+
+void StarredFilesListView::createActions()
+{
+ open_file_action_ = new QAction(tr("&Open"), this);
+ open_file_action_->setIcon(QIcon(":/images/toolbar/file-gray.png"));
+ open_file_action_->setIconVisibleInMenu(true);
+ open_file_action_->setStatusTip(tr("Open this file"));
+ connect(open_file_action_, SIGNAL(triggered()), this, SLOT(openLocalFile()));
+
+ view_file_on_web_action_ = new QAction(tr("view on &Web"), this);
+ view_file_on_web_action_->setIcon(QIcon(":/images/cloud-gray.png"));
+ view_file_on_web_action_->setIconVisibleInMenu(true);
+ view_file_on_web_action_->setStatusTip(tr("view this file on website"));
+ connect(view_file_on_web_action_, SIGNAL(triggered()), this, SLOT(viewFileOnWeb()));
+}
+
+void StarredFilesListView::openLocalFile()
+{
+ StarredItem file = qvariant_cast<StarredItem>(view_file_on_web_action_->data());
+
+ if (!file.isFile()) {
+ openLocalDir(file);
+ } else {
+ openLocalFile(file);
+ }
+}
+
+void StarredFilesListView::viewFileOnWeb()
+{
+ StarredItem file = qvariant_cast<StarredItem>(view_file_on_web_action_->data());
+
+ const Account& account = seafApplet->accountManager()->currentAccount();
+ if (account.isValid()) {
+ QString strurl;
+ if (file.type == StarredItem::REPO) {
+ strurl = "library/" + file.repo_id + "/" + file.obj_name;
+ } else if (file.type == StarredItem::DIR) {
+ strurl = "library/" + file.repo_id + file.path;
+ } else {
+ strurl = "lib/" + file.repo_id + "/file" + file.path;
+ }
+ QUrl url = account.getAbsoluteUrl(strurl);
+ QDesktopServices::openUrl(url);
+ }
+}
+
+void StarredFilesListView::updateActions()
+{
+ StarredFileItem *item = NULL;
+ QItemSelection selected = selectionModel()->selection();
+ QModelIndexList indexes = selected.indexes();
+ if (indexes.size() != 0) {
+ const QModelIndex& index = indexes.at(0);
+ QStandardItem *it = ((StarredFilesListModel *)model())->itemFromIndex(index);
+ item = (StarredFileItem *)it;
+ }
+
+ if (!item) {
+ // No item is selected
+ open_file_action_->setEnabled(false);
+ view_file_on_web_action_->setEnabled(false);
+ return;
+ }
+
+ const StarredItem& file = item->file();
+
+ open_file_action_->setData(QVariant::fromValue(file));
+ view_file_on_web_action_->setData(QVariant::fromValue(file));
+}
+
+void StarredFilesListView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPoint pos = event->pos();
+ QModelIndex index = indexAt(pos);
+ if (!index.isValid()) {
+ return;
+ }
+
+ QStandardItem *item = getFileItem(index);
+ if (!item) {
+ return;
+ }
+ updateActions();
+ QMenu *menu = prepareContextMenu((StarredFileItem *)item);
+ pos = viewport()->mapToGlobal(pos);
+ menu->exec(pos);
+}
+
+QStandardItem*
+StarredFilesListView::getFileItem(const QModelIndex &index) const
+{
+ if (!index.isValid()) {
+ return NULL;
+ }
+ const StarredFilesListModel *model = (const StarredFilesListModel*)index.model();
+ QStandardItem *item = model->itemFromIndex(index);
+ return item;
+}
+
+QMenu* StarredFilesListView::prepareContextMenu(const StarredFileItem *item)
+{
+ QMenu *menu = new QMenu(this);
+
+ menu->addAction(open_file_action_);
+ menu->addAction(view_file_on_web_action_);
+
+ return menu;
+}
+
+bool StarredFilesListView::viewportEvent(QEvent *event)
+{
+ if (event->type() != QEvent::ToolTip && event->type() != QEvent::WhatsThis) {
+ return QListView::viewportEvent(event);
+ }
+
+ QPoint global_pos = QCursor::pos();
+ QPoint viewport_pos = viewport()->mapFromGlobal(global_pos);
+ QModelIndex index = indexAt(viewport_pos);
+ if (!index.isValid()) {
+ return true;
+ }
+
+ QStandardItem *qitem = getFileItem(index);
+ if (!qitem) {
+ return true;
+ }
+
+ StarredFileItem *item = (StarredFileItem *)qitem;
+
+ QRect item_rect = visualRect(index);
+
+ QString text = "<p style='white-space:pre'>";
+ text += item->file().name();
+ text += "</p>";
+
+ QToolTip::showText(QCursor::pos(), text, viewport(), item_rect);
+
+ return true;
+}
+
+void StarredFilesListView::onItemDoubleClicked(const QModelIndex& index)
+{
+ QStandardItem *item = getFileItem(index);
+ if (!item) {
+ return;
+ }
+
+ const StarredItem& file = ((StarredFileItem *)item)->file();
+
+ if (!file.isFile()) {
+ openLocalDir(file);
+ } else {
+ openLocalFile(file);
+ }
+}
+
+void StarredFilesListView::openLocalFile(const StarredItem& file)
+{
+ RepoService::instance()->openLocalFile(file.repo_id, file.path.mid(1), this);
+}
+
+void StarredFilesListView::openLocalDir(const StarredItem& file)
+{
+ RepoService::instance()->openFolder(file.repo_id, file.path.mid(1));
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_STARRED_FILES_LIST_VIEW_H
+#define SEAFILE_CLIENT_UI_STARRED_FILES_LIST_VIEW_H
+
+#include <QListView>
+
+class QAction;
+class QContextMenuEvent;
+class QMenu;
+class QModelIndex;
+class QStandardItem;
+
+class StarredFileItem;
+class StarredItem;
+
+class StarredFilesListView : public QListView {
+ Q_OBJECT
+public:
+ StarredFilesListView(QWidget *parent=0);
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *event);
+ bool viewportEvent(QEvent *event);
+
+private slots:
+ void onItemDoubleClicked(const QModelIndex& index);
+
+private slots:
+ void openLocalFile();
+ void viewFileOnWeb();
+
+private:
+ void createActions();
+ QMenu *prepareContextMenu(const StarredFileItem *item);
+ void updateActions();
+ QStandardItem* getFileItem(const QModelIndex &index) const;
+ void openLocalFile(const StarredItem& file);
+ void openLocalDir(const StarredItem& file);
+
+ QAction *open_file_action_;
+ QAction *view_file_on_web_action_;
+ QAction *open_repo_action_;
+ QAction *gen_share_link_action;
+};
+
+#endif // SEAFILE_CLIENT_UI_STARRED_FILES_LIST_VIEW_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QTimer>
+#include <QFileInfo>
+#include <QIcon>
+#include <QStackedWidget>
+
+#include "seafile-applet.h"
+#include "account-mgr.h"
+#include "api/requests.h"
+#include "api/starred-file.h"
+#include "loading-view.h"
+#include "logout-view.h"
+#include "starred-files-list-view.h"
+#include "starred-files-list-model.h"
+#include "starred-file-item-delegate.h"
+
+#include "starred-files-tab.h"
+
+namespace {
+
+const int kRefreshInterval = 1000 * 60 * 5; // 5 min
+const char *kLoadingFaieldLabelName = "loadingFailedText";
+const char *kEmptyViewLabelName = "emptyText";
+
+enum {
+ INDEX_LOADING_VIEW = 0,
+ INDEX_LOADING_FAILED_VIEW,
+ INDEX_EMPTY_VIEW,
+ INDEX_LOGOUT_VIEW,
+ INDEX_FILES_VIEW
+};
+
+}
+
+StarredFilesTab::StarredFilesTab(QWidget *parent)
+ : TabView(parent),
+ in_refresh_(false)
+{
+ createStarredFilesListView();
+ createLoadingView();
+ createLoadingFailedView();
+
+ //createLogoutView
+ logout_view_ = new LogoutView;
+ static_cast<LogoutView*>(logout_view_)->setQssStyleForTab();
+
+ createEmptyView();
+
+ mStack->insertWidget(INDEX_LOADING_VIEW, loading_view_);
+ mStack->insertWidget(INDEX_LOADING_FAILED_VIEW, loading_failed_view_);
+ mStack->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+ mStack->insertWidget(INDEX_LOGOUT_VIEW, logout_view_);
+ mStack->insertWidget(INDEX_FILES_VIEW, files_list_view_);
+
+ refresh_timer_ = new QTimer(this);
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refresh()));
+
+ get_starred_files_req_ = NULL;
+ get_starred_items_req_ = NULL;
+
+ refresh();
+}
+
+void StarredFilesTab::createStarredFilesListView()
+{
+ files_list_view_ = new StarredFilesListView;
+ files_list_model_ = new StarredFilesListModel;
+
+ files_list_view_->setModel(files_list_model_);
+ files_list_view_->setItemDelegate(new StarredFileItemDelegate);
+}
+
+void StarredFilesTab::createLoadingView()
+{
+ loading_view_ = new LoadingView;
+ static_cast<LoadingView*>(loading_view_)->setQssStyleForTab();
+}
+
+void StarredFilesTab::createLoadingFailedView()
+{
+ loading_failed_view_ = new QWidget(this);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ loading_failed_view_->setLayout(layout);
+
+ QLabel *label = new QLabel;
+ label->setObjectName(kLoadingFaieldLabelName);
+ QString link = QString("<a style=\"color:#777\" href=\"#\">%1</a>").arg(tr("retry"));
+ QString label_text = tr("Failed to get starred files information<br/>"
+ "Please %1").arg(link);
+ label->setText(label_text);
+ label->setAlignment(Qt::AlignCenter);
+
+ connect(label, SIGNAL(linkActivated(const QString&)),
+ this, SLOT(refresh()));
+
+ layout->addWidget(label);
+}
+
+void StarredFilesTab::createEmptyView()
+{
+ empty_view_ = new QWidget(this);
+ empty_view_->setObjectName("EmptyPlaceHolder");
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ empty_view_->setLayout(layout);
+
+ QLabel *label = new QLabel;
+ label->setObjectName(kEmptyViewLabelName);
+ QString label_text = tr("You have no starred files yet.");
+ label->setText(label_text);
+ label->setAlignment(Qt::AlignCenter);
+
+ layout->addWidget(label);
+}
+
+void StarredFilesTab::refresh()
+{
+ if (!seafApplet->accountManager()->hasAccount() ||
+ !seafApplet->accountManager()->accounts().front().isValid()) {
+ mStack->setCurrentIndex(INDEX_LOGOUT_VIEW);
+ return;
+ }
+ if (in_refresh_) {
+ return;
+ }
+
+ in_refresh_ = true;
+
+ showLoadingView();
+ //AccountManager *account_mgr = seafApplet->accountManager();
+
+ const std::vector<Account>& accounts = seafApplet->accountManager()->accounts();
+ if (!seafApplet->accountManager()->hasAccount()) {
+ in_refresh_ = false;
+ return;
+ }
+
+ // server version 7.0.0 begin to support starred file dir repo
+ bool is_use_get_starred_item_api = seafApplet->accountManager()->currentAccount().isAtLeastVersion(7, 0, 0);
+
+ if (get_starred_files_req_) {
+ get_starred_files_req_->deleteLater();
+ }
+
+ if (get_starred_items_req_) {
+ get_starred_items_req_->deleteLater();
+ }
+
+ if (!is_use_get_starred_item_api) {
+ get_starred_files_req_ = new GetStarredFilesRequest(accounts[0]);
+ connect(get_starred_files_req_, SIGNAL(success(const std::vector<StarredItem>&)),
+ this, SLOT(refreshStarredFiles(const std::vector<StarredItem>&)));
+ connect(get_starred_files_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(refreshStarredFilesFailed(const ApiError&)));
+ get_starred_files_req_->send();
+ } else {
+ get_starred_items_req_ = new GetStarredFilesRequestV2(accounts[0]);
+ connect(get_starred_items_req_, SIGNAL(success(const std::vector<StarredItem>&)),
+ this, SLOT(refreshStarredFilesV2(const std::vector<StarredItem>&)));
+ connect(get_starred_items_req_, SIGNAL(failed(const ApiError&)),
+ this, SLOT(refreshStarredFilesFailed(const ApiError&)));
+ get_starred_items_req_->send();
+ }
+
+}
+
+void StarredFilesTab::refreshStarredFiles(const std::vector<StarredItem>& files)
+{
+ in_refresh_ = false;
+
+ get_starred_files_req_->deleteLater();
+ get_starred_files_req_ = NULL;
+
+ files_list_model_->setFiles(files);
+ if (files.empty()) {
+ mStack->setCurrentIndex(INDEX_EMPTY_VIEW);
+ } else {
+ mStack->setCurrentIndex(INDEX_FILES_VIEW);
+ }
+}
+
+void StarredFilesTab::refreshStarredFilesV2(const std::vector<StarredItem>& files)
+{
+ in_refresh_ = false;
+
+ get_starred_items_req_->deleteLater();
+ get_starred_items_req_ = NULL;
+
+ files_list_model_->setFiles(files);
+ if (files.empty()) {
+ mStack->setCurrentIndex(INDEX_EMPTY_VIEW);
+ } else {
+ mStack->setCurrentIndex(INDEX_FILES_VIEW);
+ }
+}
+
+void StarredFilesTab::refreshStarredFilesFailed(const ApiError& error)
+{
+ qDebug("failed to refresh starred files");
+ in_refresh_ = false;
+
+ if (mStack->currentIndex() == INDEX_LOADING_VIEW) {
+ mStack->setCurrentIndex(INDEX_LOADING_FAILED_VIEW);
+ }
+}
+
+void StarredFilesTab::showLoadingView()
+{
+ mStack->setCurrentIndex(INDEX_LOADING_VIEW);
+}
+
+void StarredFilesTab::startRefresh()
+{
+ refresh_timer_->start(kRefreshInterval);
+}
+
+void StarredFilesTab::stopRefresh()
+{
+ refresh_timer_->stop();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_STARRED_FILES_TAB_H
+#define SEAFILE_CLIENT_UI_STARRED_FILES_TAB_H
+
+#include "tab-view.h"
+
+class QTimer;
+class QListWidget;
+
+class GetStarredFilesRequest;
+class GetStarredFilesRequestV2;
+class ApiError;
+class StarredItem;
+class StarredFilesListView;
+class StarredFilesListModel;
+
+/**
+ * The starred files tab
+ */
+class StarredFilesTab : public TabView {
+ Q_OBJECT
+public:
+ explicit StarredFilesTab(QWidget *parent=0);
+
+public slots:
+ void refresh();
+
+protected:
+ void startRefresh();
+ void stopRefresh();
+
+private slots:
+ void refreshStarredFiles(const std::vector<StarredItem>& files);
+ void refreshStarredFilesV2(const std::vector<StarredItem>& files);
+ void refreshStarredFilesFailed(const ApiError& error);
+
+private:
+ void createStarredFilesListView();
+ void createLoadingView();
+ void createLoadingFailedView();
+ void createEmptyView();
+ void showLoadingView();
+
+ QTimer *refresh_timer_;
+ bool in_refresh_;
+
+ StarredFilesListView *files_list_view_;
+ StarredFilesListModel *files_list_model_;
+
+ QWidget *loading_view_;
+ QWidget *loading_failed_view_;
+ QWidget *logout_view_;
+ QWidget *empty_view_;
+
+ GetStarredFilesRequest *get_starred_files_req_;
+ GetStarredFilesRequestV2 *get_starred_items_req_;
+};
+
+#endif // SEAFILE_CLIENT_UI_STARRED_FILES_TAB_H
--- /dev/null
+#include <QtGlobal>
+
+#include <QtWidgets>
+#include <QTableView>
+#include <QResizeEvent>
+#include <QTimer>
+#include <QDesktopServices>
+#include <QCloseEvent>
+#include <QAction>
+
+#include "QtAwesome.h"
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "rpc/sync-error.h"
+#include "rpc/local-repo.h"
+#include "sync-errors-dialog.h"
+#include "ui/tray-icon.h"
+#include "sync-error-service.h"
+
+class SeafileTrayIcon;
+
+namespace {
+
+const int kUpdateErrorsIntervalMSecs = 3000;
+
+const int kDefaultColumnWidth = 120;
+const int kDefaultColumnHeight = 40;
+
+const int kRepoNameColumnWidth = 100;
+const int kPathColumnWidth = 150;
+const int kErrorColumnWidth = 200;
+const int kTimestampColumnWidth = 80;
+const int kExtraPadding = 80;
+
+const int kDefaultColumnSum = kRepoNameColumnWidth + kPathColumnWidth + kErrorColumnWidth + kTimestampColumnWidth + kExtraPadding;
+
+enum {
+ INDEX_EMPTY_VIEW = 0,
+ INDEX_TABE_VIEW
+};
+
+enum {
+ COLUMN_REPO_NAME = 0,
+ COLUMN_PATH,
+ COLUMN_ERROR_STR,
+ COLUMN_TIMESTAMP,
+ MAX_COLUMN,
+};
+
+
+} // namespace
+
+// TODO: There are lots of common logic used in FileBrowserDialog and
+// SyncErrorsDialog. We should refactor out a base dialog class.
+SyncErrorsDialog::SyncErrorsDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ // setupUi(this);
+
+ setWindowTitle(tr("File Sync Errors"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ Qt::WindowFlags flags =
+ (windowFlags() & ~Qt::WindowContextHelpButtonHint & ~Qt::Dialog) |
+ Qt::Window | Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint |
+ Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint |
+ Qt::WindowMaximizeButtonHint;
+
+ setWindowFlags(flags);
+
+ createEmptyView();
+
+ table_ = new SyncErrorsTableView;
+ model_ = new SyncErrorsTableModel(this);
+ table_->setModel(model_);
+
+ connect(table_, SIGNAL(refreshModel()), model_, SLOT(updateErrors()));
+
+ QWidget* widget = new QWidget;
+ widget->setObjectName("mainWidget");
+ QVBoxLayout* layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ setLayout(layout);
+ layout->addWidget(widget);
+
+ QVBoxLayout *vlayout = new QVBoxLayout;
+ vlayout->setContentsMargins(1, 0, 1, 0);
+ vlayout->setSpacing(0);
+ widget->setLayout(vlayout);
+
+ stack_ = new QStackedWidget;
+ stack_->insertWidget(INDEX_EMPTY_VIEW, empty_view_);
+ stack_->insertWidget(INDEX_TABE_VIEW, table_);
+ stack_->setContentsMargins(0, 0, 0, 0);
+
+ vlayout->addWidget(stack_);
+
+ onModelReset();
+ connect(model_, SIGNAL(modelReset()), this, SLOT(onModelReset()));
+}
+
+void SyncErrorsDialog::closeEvent(QCloseEvent *event)
+{
+ event->ignore();
+ this->hide();
+}
+
+void SyncErrorsDialog::updateErrors()
+{
+ model_->updateErrors();
+}
+
+void SyncErrorsDialog::onModelReset()
+{
+ if (model_->rowCount() == 0) {
+ stack_->setCurrentIndex(INDEX_EMPTY_VIEW);
+ } else {
+ stack_->setCurrentIndex(INDEX_TABE_VIEW);
+ }
+}
+
+
+void SyncErrorsDialog::createEmptyView()
+{
+ empty_view_ = new QWidget(this);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ empty_view_->setLayout(layout);
+
+ QLabel *label = new QLabel;
+ label->setText(tr("No sync errors."));
+ label->setAlignment(Qt::AlignCenter);
+
+ layout->addWidget(label);
+}
+
+SyncErrorsTableView::SyncErrorsTableView(QWidget *parent)
+ : QTableView(parent)
+{
+ verticalHeader()->hide();
+ verticalHeader()->setDefaultSectionSize(36);
+ horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
+ horizontalHeader()->setStretchLastSection(true);
+ horizontalHeader()->setCascadingSectionResizes(true);
+ horizontalHeader()->setHighlightSections(false);
+ horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
+
+ setGridStyle(Qt::NoPen);
+ setShowGrid(false);
+ setContentsMargins(0, 0, 0, 0);
+ setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+ setMouseTracking(true);
+
+ createContextMenu();
+
+ connect(this, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onItemDoubleClicked(const QModelIndex&)));
+}
+
+void SyncErrorsTableView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QPoint pos = event->pos();
+ int row = rowAt(pos.y());
+ qDebug("row = %d\n", row);
+ if (row == -1) {
+ return;
+ }
+
+ SyncErrorsTableModel *model = (SyncErrorsTableModel *)this->model();
+
+ SyncError error = model->errorAt(row);
+
+ QModelIndexList selected = selectionModel()->selectedRows();
+ selected_sync_errors_.clear();
+ foreach(const QModelIndex &index, selected) {
+ selected_sync_errors_.append(model->errorAt(index.row()));
+ }
+
+ prepareContextMenu(error);
+ pos = viewport()->mapToGlobal(pos);
+ context_menu_->exec(pos);
+}
+
+void SyncErrorsTableView::prepareContextMenu(const SyncError& error)
+{
+ id_ = error.id;
+}
+
+void SyncErrorsTableView::onDeleteFileAsyncError()
+{
+ foreach(const SyncError& error, selected_sync_errors_) {
+ bool success = seafApplet->rpcClient()->deleteFileAsyncErrorById(error.id);
+ if (!success) {
+ seafApplet->messageBox(tr("Delete file sync error failed"));
+ return;
+ }
+ }
+ emit refreshModel();
+}
+
+void SyncErrorsTableView::createContextMenu()
+{
+ context_menu_ = new QMenu(this);
+ delete_action_ = new QAction(tr("delete"), this);
+ context_menu_->addAction(delete_action_);
+ connect(delete_action_, SIGNAL(triggered()), this, SLOT(onDeleteFileAsyncError()));
+}
+
+void SyncErrorsTableView::resizeEvent(QResizeEvent *event)
+{
+ QTableView::resizeEvent(event);
+ SyncErrorsTableModel *m = (SyncErrorsTableModel *)(model());
+ m->onResize(event->size());
+}
+
+void SyncErrorsTableView::onItemDoubleClicked(const QModelIndex& index)
+{
+ SyncErrorsTableModel *model = (SyncErrorsTableModel *)this->model();
+ SyncError error = model->errorAt(index.row());
+
+ // printf("error repo id is %s\n", error.repo_id.toUtf8().data());
+ if (!error.repo_id.isEmpty()) {
+ LocalRepo repo;
+ seafApplet->rpcClient()->getLocalRepo(error.repo_id, &repo);
+ if (repo.isValid()) {
+ QDesktopServices::openUrl(QUrl::fromLocalFile(repo.worktree));
+ }
+ }
+}
+
+SyncErrorsTableModel::SyncErrorsTableModel(QObject *parent)
+ : QAbstractTableModel(parent),
+ repo_name_column_width_(kRepoNameColumnWidth),
+ path_column_width_(kPathColumnWidth),
+ error_column_width_(kErrorColumnWidth)
+{
+ update_timer_ = new QTimer(this);
+ connect(update_timer_, SIGNAL(timeout()), this, SLOT(updateErrors()));
+ update_timer_->start(kUpdateErrorsIntervalMSecs);
+
+ connect(this, SIGNAL(sigSyncErrorUpdated()), seafApplet->trayIcon(), SLOT(slotSyncErrorUpdate()));
+ LastSyncError::instance()->start();
+ current_id_ = LastSyncError::instance()->getLastSyncErrorID();
+ updateErrors();
+}
+
+void SyncErrorsTableModel::updateErrors()
+{
+ std::vector<SyncError> errors;
+ bool success = seafApplet->rpcClient()->getSyncErrors(&errors, 0, 50);
+ if (!success) {
+ qDebug("failed to get sync errors");
+ return;
+ }
+ if (errors.size() > 0) {
+ if (current_id_ != errors[0].id) {
+ current_id_ = errors[0].id;
+ LastSyncError::instance()->saveLatestErrorID(current_id_);
+ emit sigSyncErrorUpdated();
+ }
+ }
+
+
+ // SyncError fake_error;
+ // fake_error.repo_id = "xxx";
+ // fake_error.repo_name = "NotSoGood";
+ // fake_error.path = "/tmp/NotSoGood/BadFile";
+ // fake_error.error_id = 5;
+ // fake_error.timestamp = 1483056000;
+ // fake_error.translateErrorStr();
+ // errors.push_back(fake_error);
+
+ if (errors_ == errors) {
+ return;
+ }
+
+ if (errors_.size() != errors.size()) {
+ beginResetModel();
+ errors_ = errors;
+ endResetModel();
+ return;
+ }
+
+ for (int i = 0, n = errors.size(); i < n; i++) {
+ if (errors_[i] == errors[i]) {
+ continue;
+ }
+
+ errors_[i] = errors[i];
+ QModelIndex start = QModelIndex().child(i, 0);
+ QModelIndex stop = QModelIndex().child(i, MAX_COLUMN - 1);
+ emit dataChanged(start, stop);
+ }
+}
+
+int SyncErrorsTableModel::rowCount(const QModelIndex& parent) const
+{
+ return errors_.size();
+}
+
+int SyncErrorsTableModel::columnCount(const QModelIndex& parent) const
+{
+ return MAX_COLUMN;
+}
+
+void SyncErrorsTableModel::onResize(const QSize &size)
+{
+ int extra_width = size.width() - kDefaultColumnSum;
+ int extra_width_per_column = extra_width / 3;
+
+ repo_name_column_width_ = kRepoNameColumnWidth + extra_width_per_column;
+ path_column_width_ = kPathColumnWidth + extra_width_per_column;
+ error_column_width_ = kErrorColumnWidth + extra_width_per_column;
+
+ // name_column_width_ should be always larger than kPathColumnWidth
+ if (errors_.empty())
+ return;
+
+ // printf ("path_column_width_ = %d\n", path_column_width_);
+ emit dataChanged(
+ index(0, COLUMN_ERROR_STR),
+ index(errors_.size() - 1 , COLUMN_ERROR_STR));
+}
+
+QVariant SyncErrorsTableModel::data(const QModelIndex & index, int role) const
+{
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ int column = index.column();
+
+ if (role == Qt::TextAlignmentRole)
+ return Qt::AlignLeft + Qt::AlignVCenter;
+
+ if (role == Qt::ToolTipRole)
+ return tr("Double click to open the library");
+
+ if (role == Qt::SizeHintRole) {
+ int h = kDefaultColumnHeight;
+ int w = kDefaultColumnWidth;
+ switch (column) {
+ case COLUMN_REPO_NAME:
+ w = repo_name_column_width_;
+ break;
+ case COLUMN_PATH:
+ w = path_column_width_;
+ break;
+ case COLUMN_ERROR_STR:
+ w = error_column_width_;
+ break;
+ case COLUMN_TIMESTAMP:
+ w = kTimestampColumnWidth;
+ break;
+ default:
+ break;
+ }
+ return QSize(w, h);
+ }
+
+ if (role != Qt::DisplayRole) {
+ return QVariant();
+ }
+
+ const SyncError &error = errors_[index.row()];
+
+ if (column == COLUMN_REPO_NAME) {
+ return error.repo_name;
+ } else if (column == COLUMN_PATH) {
+ return QDir::toNativeSeparators(error.path);
+ } else if (column == COLUMN_ERROR_STR) {
+ return error.error_str;
+ } else if (column == COLUMN_TIMESTAMP) {
+ return error.readable_time_stamp;
+ }
+
+ return QVariant();
+}
+
+QVariant SyncErrorsTableModel::headerData(int section,
+ Qt::Orientation orientation,
+ int role) const
+{
+ if (orientation == Qt::Vertical) {
+ return QVariant();
+ }
+
+ if (role == Qt::TextAlignmentRole)
+ return Qt::AlignLeft + Qt::AlignVCenter;
+
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (section == COLUMN_REPO_NAME) {
+ return tr("Library");
+ } else if (section == COLUMN_PATH) {
+ return tr("Path");
+ } else if (section == COLUMN_ERROR_STR) {
+ return tr("Error");
+ } else if (section == COLUMN_TIMESTAMP) {
+ return tr("Time");
+ }
+
+
+ return QVariant();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SYNC_ERRORS_DIALOG_H
+#define SEAFILE_CLIENT_SYNC_ERRORS_DIALOG_H
+
+#include <vector>
+
+#include <QTableView>
+#include <QHeaderView>
+#include <QAbstractTableModel>
+#include <QDialog>
+
+#include "rpc/sync-error.h"
+
+class QTimer;
+class QStackedWidget;
+class QSizeGrip;
+class QLabel;
+class QEvent;
+
+class SyncError;
+class SyncErrorsTableView;
+class SyncErrorsTableModel;
+
+class SyncErrorsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ SyncErrorsDialog(QWidget *parent=0);
+ void updateErrors();
+
+ void closeEvent(QCloseEvent *event);
+
+private slots:
+ void onModelReset();
+
+private:
+ void createEmptyView();
+
+ QLabel *brand_label_;
+ QPushButton *minimize_button_;
+ QPushButton *close_button_;
+ QPoint old_pos_;
+
+ QSizeGrip *resizer_;
+
+ QStackedWidget *stack_;
+ SyncErrorsTableView *table_;
+ SyncErrorsTableModel *model_;
+ QWidget *empty_view_;
+};
+
+class SyncErrorsTableView : public QTableView
+{
+ Q_OBJECT
+
+public:
+ SyncErrorsTableView(QWidget *parent=0);
+
+ void contextMenuEvent(QContextMenuEvent *event);
+ void resizeEvent(QResizeEvent *event);
+signals:
+ void refreshModel();
+
+private slots:
+ void onItemDoubleClicked(const QModelIndex& index);
+ void onDeleteFileAsyncError();
+
+private:
+ void createContextMenu();
+ void prepareContextMenu(const SyncError& error);
+
+private:
+ QMenu *context_menu_;
+ QAction *delete_action_;
+ int id_;
+ QList<SyncError> selected_sync_errors_;
+};
+
+
+class SyncErrorsTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+public:
+ SyncErrorsTableModel(QObject *parent=0);
+
+ int rowCount(const QModelIndex& parent=QModelIndex()) const;
+ int columnCount(const QModelIndex& parent=QModelIndex()) const;
+ QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ SyncError errorAt(size_t i) const { return (i >= errors_.size()) ? SyncError() : errors_[i]; }
+
+ void onResize(const QSize& size);
+
+signals:
+ void sigSyncErrorUpdated();
+
+public slots:
+ void updateErrors();
+
+private:
+
+ std::vector<SyncError> errors_;
+ QTimer *update_timer_;
+ int repo_name_column_width_;
+ int path_column_width_;
+ int error_column_width_;
+ int current_id_ = 0;
+};
+
+#endif // SEAFILE_CLIENT_SYNC_ERRORS_DIALOG_H
--- /dev/null
+#include <QStackedWidget>
+#include <QVBoxLayout>
+
+#include "tab-view.h"
+
+TabView::TabView(QWidget *parent)
+ : QWidget (parent)
+{
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(layout);
+
+ mStack = new QStackedWidget;
+ layout->addWidget(mStack);
+}
+
+void TabView::showEvent(QShowEvent *event)
+{
+ startRefresh();
+ QWidget::showEvent(event);
+}
+
+/**
+ * Pause its freshing when this tab is not shown in front.
+ */
+void TabView::hideEvent(QHideEvent *event)
+{
+ stopRefresh();
+ QWidget::hideEvent(event);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_TAB_VIEW_H
+#define SEAFILE_CLIENT_UI_TAB_VIEW_H
+
+#include <QWidget>
+
+class QStackedWidget;
+class QShowEvent;
+class QHideEvent;
+
+/**
+ * Represents one tab of a QTabWidget
+ */
+class TabView : public QWidget {
+ Q_OBJECT
+public:
+ TabView(QWidget *parent=0);
+ virtual ~TabView() {};
+
+public slots:
+ virtual void refresh() = 0;
+
+protected:
+ virtual void showEvent(QShowEvent *event);
+ virtual void hideEvent(QHideEvent *event);
+
+ virtual void startRefresh() = 0;
+ virtual void stopRefresh() = 0;
+
+ QStackedWidget *mStack;
+};
+
+#endif // SEAFILE_CLIENT_UI_TAB_VIEW_H
--- /dev/null
+#include <stdlib.h>
+
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+#include <QApplication>
+#include <QDesktopServices>
+#include <QSet>
+#include <QDebug>
+#include <QMenuBar>
+#include <QRunnable>
+#include <QSysInfo>
+#include <QCoreApplication>
+
+#include "rpc/local-repo.h"
+#include "utils/utils.h"
+#include "utils/utils-mac.h"
+#include "utils/file-utils.h"
+#include "seafile-applet.h"
+#include "configurator.h"
+#include "rpc/rpc-client.h"
+#include "main-window.h"
+#include "settings-dialog.h"
+#include "settings-mgr.h"
+#include "server-status-service.h"
+#include "api/commit-details.h"
+#include "sync-errors-dialog.h"
+#include "account-mgr.h"
+#include "filebrowser/progress-dialog.h"
+
+#include "tray-icon.h"
+#if defined(Q_OS_MAC)
+#include "traynotificationmanager.h"
+// QT's platform apis
+// http://qt-project.org/doc/qt-4.8/exportedfunctions.html
+extern void qt_mac_set_dock_menu(QMenu *menu);
+#endif
+#include "utils/utils-mac.h"
+
+#if defined(Q_OS_LINUX)
+#include <QDBusConnection>
+#include <QDBusMessage>
+#include <QDBusPendingCall>
+#endif
+
+#include "src/ui/about-dialog.h"
+#if defined(Q_OS_WIN32)
+#include "utils/utils-win.h"
+#endif
+
+namespace {
+
+const int kRefreshInterval = 1000;
+const int kRotateTrayIconIntervalMilli = 250;
+const int kMessageDisplayTimeMSecs = 5000;
+#if defined(Q_OS_WIN32)
+const QString kShellExtFixExecutableName = "shellext-fix.exe";
+const QString kShellFixLogName = "shellext-fix.log";
+#endif
+#ifdef Q_OS_MAC
+void darkmodeWatcher(bool /*new Value*/) {
+ seafApplet->trayIcon()->reloadTrayIcon();
+}
+#endif
+
+QString folderToShow(const CommitDetails& details, const QString& worktree)
+{
+ QString path = worktree;
+ if (!details.added_files.empty()) {
+ path = pathJoin(worktree, details.added_files[0]);
+ } else if (!details.modified_files.empty()) {
+ path = pathJoin(worktree, details.modified_files[0]);
+ } else if (!details.added_dirs.empty()) {
+ path = pathJoin(worktree, details.added_dirs[0]);
+ } else if (!details.renamed_files.empty()) {
+ path = pathJoin(worktree, details.renamed_files[0].second);
+ } else if (!details.deleted_files.empty()) {
+ path = getParentPath(pathJoin(worktree, details.deleted_files[0]));
+ } else if (!details.deleted_dirs.empty()) {
+ path = getParentPath(pathJoin(worktree, details.deleted_dirs[0]));
+ }
+ return path;
+}
+
+// Read the commit diff from daemon rpc. We need to run it in a separate thread
+// since this may block for a while.
+class DiffReader : public QRunnable
+{
+public:
+ DiffReader(const LocalRepo &repo,
+ const QString &previous_commit_id,
+ const QString &commit_id)
+ : repo_(repo),
+ commit_id_(commit_id),
+ previous_commit_id_(previous_commit_id){};
+
+ void run()
+ {
+ CommitDetails details;
+ seafApplet->rpcClient()->getCommitDiff(
+ repo_.id, previous_commit_id_, commit_id_, &details);
+ showInGraphicalShell(folderToShow(details, repo_.worktree));
+ }
+
+private:
+ const LocalRepo repo_;
+ const QString commit_id_;
+ const QString previous_commit_id_;
+};
+
+} // namespace
+
+SeafileTrayIcon::SeafileTrayIcon(QObject *parent)
+ : QSystemTrayIcon(parent),
+ nth_trayicon_(0),
+ rotate_counter_(0),
+ state_(STATE_DAEMON_UP),
+ next_message_msec_(0),
+ sync_errors_dialog_(nullptr),
+ about_dialog_(nullptr),
+ log_dir_uploader_(nullptr)
+{
+ setState(STATE_DAEMON_DOWN);
+ rotate_timer_ = new QTimer(this);
+ connect(rotate_timer_, SIGNAL(timeout()), this, SLOT(rotateTrayIcon()));
+
+ refresh_timer_ = new QTimer(this);
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refreshTrayIcon()));
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(refreshTrayIconToolTip()));
+#if defined(Q_OS_WIN32)
+ connect(refresh_timer_, SIGNAL(timeout()), this, SLOT(checkTrayIconMessageQueue()));
+#endif
+
+ createActions();
+ createContextMenu();
+
+ connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
+ this, SLOT(onActivated(QSystemTrayIcon::ActivationReason)));
+
+#if !defined(Q_OS_LINUX)
+ connect(this, SIGNAL(messageClicked()),
+ this, SLOT(onMessageClicked()));
+#endif
+
+ hide();
+
+ createGlobalMenuBar();
+#if defined(Q_OS_MAC)
+ tnm = new TrayNotificationManager(this);
+#endif
+}
+
+void SeafileTrayIcon::start()
+{
+ show();
+ refresh_timer_->start(kRefreshInterval);
+#if defined(Q_OS_MAC)
+ utils::mac::set_darkmode_watcher(&darkmodeWatcher);
+#endif
+ sync_errors_dialog_ = new SyncErrorsDialog;
+ sync_errors_dialog_->updateErrors();
+}
+
+void SeafileTrayIcon::createActions()
+{
+ disable_auto_sync_action_ = new QAction(tr("Disable auto sync"), this);
+ connect(disable_auto_sync_action_, SIGNAL(triggered()), this, SLOT(disableAutoSync()));
+
+ enable_auto_sync_action_ = new QAction(tr("Enable auto sync"), this);
+ connect(enable_auto_sync_action_, SIGNAL(triggered()), this, SLOT(enableAutoSync()));
+
+ quit_action_ = new QAction(tr("&Quit"), this);
+ connect(quit_action_, SIGNAL(triggered()), this, SLOT(quitSeafile()));
+
+ show_main_window_action_ = new QAction(tr("Show main window"), this);
+ connect(show_main_window_action_, SIGNAL(triggered()), this, SLOT(showMainWindow()));
+
+ settings_action_ = new QAction(tr("Settings"), this);
+ connect(settings_action_, SIGNAL(triggered()), this, SLOT(showSettingsWindow()));
+
+ open_seafile_folder_action_ = new QAction(tr("Open %1 &folder").arg(getBrand()), this);
+ open_seafile_folder_action_->setStatusTip(tr("open %1 folder").arg(getBrand()));
+ connect(open_seafile_folder_action_, SIGNAL(triggered()), this, SLOT(openSeafileFolder()));
+
+#if defined(Q_OS_WIN32)
+ shellext_fix_action_ = new QAction(tr("Repair explorer extension"), this);
+ connect(shellext_fix_action_, SIGNAL(triggered()), this, SLOT(shellExtFix()));
+#endif
+ open_log_directory_action_ = new QAction(tr("Open &logs folder"), this);
+ open_log_directory_action_->setStatusTip(tr("open %1 log folder").arg(getBrand()));
+ connect(open_log_directory_action_, SIGNAL(triggered()), this, SLOT(openLogDirectory()));
+
+ upload_log_directory_action_ = new QAction(tr("Upload log files"), this);
+ upload_log_directory_action_->setStatusTip(tr("upload %1 log files").arg(getBrand()));
+ connect(upload_log_directory_action_, SIGNAL(triggered()), this, SLOT(uploadLogDirectory()));
+
+ show_sync_errors_action_ = new QAction(tr("Show file sync errors"), this);
+ show_sync_errors_action_->setStatusTip(tr("Show file sync errors"));
+ connect(show_sync_errors_action_, SIGNAL(triggered()), this, SLOT(showSyncErrorsDialog()));
+
+ about_action_ = new QAction(tr("&About"), this);
+ about_action_->setStatusTip(tr("Show the application's About box"));
+ connect(about_action_, SIGNAL(triggered()), this, SLOT(about()));
+
+ open_help_action_ = new QAction(tr("&Online help"), this);
+ open_help_action_->setStatusTip(tr("open %1 online help").arg(getBrand()));
+ connect(open_help_action_, SIGNAL(triggered()), this, SLOT(openHelp()));
+}
+
+void SeafileTrayIcon::createContextMenu()
+{
+ // help_menu_ = new QMenu(tr("Help"), NULL);
+ // help_menu_->addAction(about_action_);
+ // help_menu_->addAction(open_help_action_);
+
+ context_menu_ = new QMenu(NULL);
+ context_menu_->addAction(show_main_window_action_);
+ context_menu_->addAction(open_seafile_folder_action_);
+ context_menu_->addAction(settings_action_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(open_log_directory_action_);
+ #if defined(Q_OS_WIN32)
+ context_menu_->addAction(shellext_fix_action_);
+ #endif
+ context_menu_->addSeparator();
+ //context_menu_->addAction(upload_log_directory_action_);
+ context_menu_->addAction(show_sync_errors_action_);
+ // context_menu_->addMenu(help_menu_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(about_action_);
+ context_menu_->addAction(open_help_action_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(enable_auto_sync_action_);
+ context_menu_->addAction(disable_auto_sync_action_);
+ context_menu_->addSeparator();
+ context_menu_->addAction(quit_action_);
+
+ setContextMenu(context_menu_);
+ connect(context_menu_, SIGNAL(aboutToShow()), this, SLOT(prepareContextMenu()));
+}
+
+void SeafileTrayIcon::prepareContextMenu()
+{
+ if (seafApplet->settingsManager()->autoSync()) {
+ enable_auto_sync_action_->setVisible(false);
+ disable_auto_sync_action_->setVisible(true);
+ } else {
+ enable_auto_sync_action_->setVisible(true);
+ disable_auto_sync_action_->setVisible(false);
+ }
+
+ std::vector<SyncError> errors;
+ bool success = seafApplet->rpcClient()->getSyncErrors(&errors, 0, 1);
+ if (!success) {
+ qDebug("failed to get sync errors");
+ return;
+ }
+
+ if (errors.empty()) {
+ show_sync_errors_action_->setEnabled(false);
+ } else {
+ show_sync_errors_action_->setEnabled(true);
+ }
+}
+
+void SeafileTrayIcon::createGlobalMenuBar()
+{
+ // support it only on mac os x currently
+ // TODO: destroy the objects when seafile closes
+#ifdef Q_OS_MAC
+ // create qmenu used in menubar and docker menu
+ global_menu_ = new QMenu(tr("File"));
+ global_menu_->addAction(show_main_window_action_);
+ global_menu_->addAction(open_seafile_folder_action_);
+ global_menu_->addAction(settings_action_);
+ global_menu_->addAction(open_log_directory_action_);
+ //global_menu_->addAction(upload_log_directory_action_);
+ global_menu_->addAction(show_sync_errors_action_);
+ global_menu_->addSeparator();
+ global_menu_->addAction(enable_auto_sync_action_);
+ global_menu_->addAction(disable_auto_sync_action_);
+
+ global_menubar_ = new QMenuBar(0);
+ global_menubar_->addMenu(global_menu_);
+ // TODO fix the line below which crashes under qt5.4.0
+ //global_menubar_->addMenu(help_menu_);
+ global_menubar_->setNativeMenuBar(true);
+ qApp->setAttribute(Qt::AA_DontUseNativeMenuBar, false);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
+ global_menu_->setAsDockMenu(); // available after qt5.2.0
+#else
+ qt_mac_set_dock_menu(global_menu_); // deprecated in latest qt
+#endif
+ // create QMenuBar that has no parent, so we can share the global menubar
+#endif // Q_OS_MAC
+}
+
+void SeafileTrayIcon::rotate(bool start)
+{
+ /* tray icon should not be refreshed on Gnome according to their guidelines */
+#if defined(Q_OS_LINUX)
+ const char *env = g_getenv("DESKTOP_SESSION");
+ if (env != NULL &&
+ (strcmp(env, "gnome") == 0 || strcmp(env, "gnome-wayland") == 0)) {
+ return;
+ }
+#endif
+
+ if (start) {
+ rotate_counter_ = 0;
+ if (!rotate_timer_->isActive()) {
+ nth_trayicon_ = 0;
+ rotate_timer_->start(kRotateTrayIconIntervalMilli);
+ }
+ } else {
+ rotate_timer_->stop();
+ }
+}
+
+void SeafileTrayIcon::showMessage(const QString &title,
+ const QString &message,
+ const QString &repo_id,
+ const QString &commit_id,
+ const QString &previous_commit_id,
+ MessageIcon icon,
+ int millisecondsTimeoutHint,
+ bool is_error_message)
+{
+ is_error_message_ = is_error_message;
+#ifdef Q_OS_MAC
+ repo_id_ = repo_id;
+ commit_id_ = commit_id;
+ previous_commit_id_ = previous_commit_id;
+ if (QSysInfo::MacintoshVersion < QSysInfo::MV_MOUNTAINLION) {
+ // qWarning("using old style notifications");
+ QIcon info_icon(":/images/info.png");
+ TrayNotificationWidget* trayNotification = new TrayNotificationWidget(info_icon.pixmap(32, 32), title, message);
+ tnm->append(trayNotification);
+ return;
+ }
+ // qWarning("using new style notifications");
+
+ QSystemTrayIcon::showMessage(title, message, icon, millisecondsTimeoutHint);
+#elif defined(Q_OS_LINUX)
+ repo_id_ = repo_id;
+ Q_UNUSED(icon);
+ QVariantMap hints;
+ QString brand = getBrand();
+ hints["resident"] = QVariant(true);
+ hints["desktop-entry"] = QVariant(brand);
+ QList<QVariant> args = QList<QVariant>() << brand << quint32(0) << brand
+ << title << message << QStringList () << hints << qint32(-1);
+ QDBusMessage method = QDBusMessage::createMethodCall("org.freedesktop.Notifications","/org/freedesktop/Notifications", "org.freedesktop.Notifications", "Notify");
+ method.setArguments(args);
+ QDBusConnection::sessionBus().asyncCall(method);
+#else
+ TrayMessage msg;
+ msg.title = title;
+ msg.message = message;
+ msg.icon = icon;
+ msg.repo_id = repo_id;
+ msg.commit_id = commit_id;
+ msg.previous_commit_id = previous_commit_id;
+ pending_messages_.enqueue(msg);
+#endif
+}
+
+void SeafileTrayIcon::rotateTrayIcon()
+{
+ if (rotate_counter_ >= 8 || !seafApplet->settingsManager()->autoSync()) {
+ rotate_timer_->stop();
+ if (!seafApplet->settingsManager()->autoSync())
+ setState (STATE_DAEMON_AUTOSYNC_DISABLED);
+ else
+ setState (STATE_DAEMON_UP);
+ return;
+ }
+
+ TrayState states[] = { STATE_TRANSFER_1, STATE_TRANSFER_2 };
+ int index = nth_trayicon_ % 2;
+ setIcon(stateToIcon(states[index]));
+
+ nth_trayicon_++;
+ rotate_counter_++;
+}
+
+void SeafileTrayIcon::setState(TrayState state, const QString& tip)
+{
+ if (state_ == state) {
+ return;
+ }
+
+ QString tool_tip = tip.isEmpty() ? getBrand() : tip;
+
+ setIcon(stateToIcon(state));
+ setToolTip(tool_tip);
+}
+
+void SeafileTrayIcon::reloadTrayIcon()
+{
+ setIcon(stateToIcon(state_));
+
+#if defined(Q_OS_LINUX)
+ hide();
+ show();
+#endif
+}
+
+QIcon SeafileTrayIcon::getIcon(const QString& name)
+{
+ if (icon_cache_.contains(name)) {
+ return icon_cache_[name];
+ }
+
+ QIcon icon(name);
+ icon_cache_[name] = icon;
+ return icon;
+}
+
+QIcon SeafileTrayIcon::stateToIcon(TrayState state)
+{
+ state_ = state;
+#if defined(Q_OS_WIN32)
+ QString icon_name;
+ switch (state) {
+ case STATE_DAEMON_UP:
+ icon_name = ":/images/win/daemon_up.ico";
+ break;
+ case STATE_DAEMON_DOWN:
+ icon_name = ":/images/win/daemon_down.ico";
+ break;
+ case STATE_DAEMON_AUTOSYNC_DISABLED:
+ icon_name = ":/images/win/seafile_auto_sync_disabled.ico";
+ break;
+ case STATE_TRANSFER_1:
+ icon_name = ":/images/win/seafile_transfer_1.ico";
+ break;
+ case STATE_TRANSFER_2:
+ icon_name = ":/images/win/seafile_transfer_2.ico";
+ break;
+ case STATE_SERVERS_NOT_CONNECTED:
+ icon_name = ":/images/win/seafile_warning.ico";
+ break;
+ case STATE_HAVE_UNREAD_MESSAGE:
+ icon_name = ":/images/win/notification.ico";
+ break;
+ }
+ return getIcon(icon_name);
+#elif defined(Q_OS_MAC)
+ bool isDarkMode = utils::mac::is_darkmode();
+ // filename = icon_name + ?white + .png
+ QString icon_name;
+
+ switch (state) {
+ case STATE_DAEMON_UP:
+ icon_name = ":/images/mac/daemon_up";
+ break;
+ case STATE_DAEMON_DOWN:
+ icon_name = ":/images/mac/daemon_down.png";
+ break;
+ case STATE_DAEMON_AUTOSYNC_DISABLED:
+ icon_name = ":/images/mac/seafile_auto_sync_disabled";
+ break;
+ case STATE_TRANSFER_1:
+ icon_name = ":/images/mac/seafile_transfer_1";
+ break;
+ case STATE_TRANSFER_2:
+ icon_name = ":/images/mac/seafile_transfer_2";
+ break;
+ case STATE_SERVERS_NOT_CONNECTED:
+ icon_name = ":/images/mac/seafile_warning";
+ break;
+ case STATE_HAVE_UNREAD_MESSAGE:
+ icon_name = ":/images/mac/notification";
+ break;
+ }
+ return getIcon(icon_name + (isDarkMode ? "_white" : "") + ".png");
+#else
+ QString icon_name;
+ switch (state) {
+ case STATE_DAEMON_UP:
+ icon_name = ":/images/daemon_up.png";
+ break;
+ case STATE_DAEMON_DOWN:
+ icon_name = ":/images/daemon_down.png";
+ break;
+ case STATE_DAEMON_AUTOSYNC_DISABLED:
+ icon_name = ":/images/seafile_auto_sync_disabled.png";
+ break;
+ case STATE_TRANSFER_1:
+ icon_name = ":/images/seafile_transfer_1.png";
+ break;
+ case STATE_TRANSFER_2:
+ icon_name = ":/images/seafile_transfer_2.png";
+ break;
+ case STATE_SERVERS_NOT_CONNECTED:
+ icon_name = ":/images/seafile_warning.png";
+ break;
+ case STATE_HAVE_UNREAD_MESSAGE:
+ icon_name = ":/images/notification.png";
+ break;
+ }
+ return getIcon(icon_name);
+#endif
+}
+
+void SeafileTrayIcon::showMainWindow()
+{
+ MainWindow *main_win = seafApplet->mainWindow();
+ main_win->showWindow();
+}
+
+void SeafileTrayIcon::about()
+{
+ if (!about_dialog_) {
+ about_dialog_ = new AboutDialog();
+ }
+ about_dialog_->show();
+ about_dialog_->raise();
+ about_dialog_->activateWindow();
+ return;
+
+// QMessageBox::about(seafApplet->mainWindow(), tr("About %1").arg(getBrand()),
+// tr("<h2>%1 Client %2</h2>").arg(getBrand()).arg(
+// STRINGIZE(SEAFILE_CLIENT_VERSION))
+// #if defined(SEAFILE_CLIENT_REVISION)
+// .append("<h4> REV %1 </h4>")
+// .arg(STRINGIZE(SEAFILE_CLIENT_REVISION))
+// #endif
+// );
+}
+
+void SeafileTrayIcon::openHelp()
+{
+ QString url;
+ if (QLocale::system().name() == "zh_CN") {
+ url = "https://cloud.seafile.com/published/seafile-user-manual/syncing_client/install_syncing_client.md";
+ } else {
+ url = "https://download.seafile.com/published/seafile-user-manual/syncing_client/install_sync.md";
+ }
+
+ QDesktopServices::openUrl(QUrl(url));
+}
+
+void SeafileTrayIcon::openSeafileFolder()
+{
+ QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(seafApplet->configurator()->seafileDir()).path()));
+}
+
+void SeafileTrayIcon::shellExtFix()
+{
+#if defined(Q_OS_WIN32)
+ QString application_dir = QCoreApplication::applicationDirPath();
+ QString shellext_fix_path = pathJoin(application_dir, kShellExtFixExecutableName);
+ shellext_fix_path = QString("\"%1\"").arg(shellext_fix_path);
+
+ QString log_dir = QDir(seafApplet->configurator()->ccnetDir()).absoluteFilePath("logs");
+ QString log_path = pathJoin(log_dir, kShellFixLogName);
+
+ qWarning("will exec shellext fix command is: %s, the log path is: %s",
+ toCStr(shellext_fix_path),
+ toCStr(log_path));
+
+ DWORD res = utils::win::runShellAsAdministrator(toCStr(shellext_fix_path), toCStr(log_path), SW_HIDE);
+ if (res == 0) {
+ seafApplet->warningBox(tr("Successfully fixed sync status icons for Explorer"));
+
+ } else {
+ seafApplet->warningBox(tr("Faild to fix sync status icons for Explorer"));
+ qWarning("faild to fix sync status icons for explorer");
+ }
+
+#endif
+}
+
+void SeafileTrayIcon::openLogDirectory()
+{
+ QString log_path = QDir(seafApplet->configurator()->ccnetDir()).absoluteFilePath("logs");
+ QDesktopServices::openUrl(QUrl::fromLocalFile(log_path));
+}
+
+void SeafileTrayIcon::uploadLogDirectory()
+{
+ if (!seafApplet->accountManager()->currentAccount().isValid()) {
+ seafApplet->warningBox(tr("Please login first"));
+ return;
+ }
+
+ if (log_dir_uploader_ == nullptr) {
+ log_dir_uploader_ = new LogDirUploader();
+ connect(log_dir_uploader_, SIGNAL(finished()), this, SLOT(clearUploader()));
+ log_dir_uploader_->start();
+ }
+}
+
+void SeafileTrayIcon::clearUploader()
+{
+ log_dir_uploader_ = nullptr;
+}
+
+void SeafileTrayIcon::showSettingsWindow()
+{
+ seafApplet->settingsDialog()->show();
+ seafApplet->settingsDialog()->raise();
+ seafApplet->settingsDialog()->activateWindow();
+}
+
+void SeafileTrayIcon::slotSyncErrorUpdate() {
+ setSyncErrorStatus(true);
+}
+
+void SeafileTrayIcon::onActivated(QSystemTrayIcon::ActivationReason reason)
+{
+#if !defined(Q_OS_MAC)
+ switch(reason) {
+ case QSystemTrayIcon::Trigger: // single click
+ case QSystemTrayIcon::MiddleClick:
+ case QSystemTrayIcon::DoubleClick:
+ showMainWindow();
+ break;
+ default:
+ return;
+ }
+#endif
+}
+
+void SeafileTrayIcon::disableAutoSync()
+{
+ seafApplet->settingsManager()->setAutoSync(false);
+}
+
+void SeafileTrayIcon::enableAutoSync()
+{
+ seafApplet->settingsManager()->setAutoSync(true);
+}
+
+void SeafileTrayIcon::quitSeafile()
+{
+ QCoreApplication::exit(0);
+}
+
+void SeafileTrayIcon::refreshTrayIcon()
+{
+ if (rotate_timer_->isActive()) {
+ return;
+ }
+
+ if (!seafApplet->settingsManager()->autoSync()) {
+ setState(STATE_DAEMON_AUTOSYNC_DISABLED,
+ tr("auto sync is disabled"));
+ return;
+ }
+
+ if (!ServerStatusService::instance()->allServersConnected()) {
+ setState(STATE_SERVERS_NOT_CONNECTED, tr("some servers not connected"));
+ return;
+ }
+
+ if (haveSyncError()) {
+ setState(STATE_SERVERS_NOT_CONNECTED, tr("have some sync error"));
+ return;
+ }
+
+ setState(STATE_DAEMON_UP);
+}
+
+void SeafileTrayIcon::refreshTrayIconToolTip()
+{
+ if (!seafApplet->settingsManager()->autoSync())
+ return;
+
+ int up_rate, down_rate;
+ if (seafApplet->rpcClient()->getUploadRate(&up_rate) < 0 ||
+ seafApplet->rpcClient()->getDownloadRate(&down_rate) < 0) {
+ return;
+ }
+
+ if (up_rate <= 0 && down_rate <= 0) {
+ return;
+ }
+
+ QString uploadStr = tr("Uploading");
+ QString downloadStr = tr("Downloading");
+ if (up_rate > 0 && down_rate > 0) {
+ setToolTip(QString("%1 %2/s, %3 %4/s\n").
+ arg(uploadStr).arg(readableFileSize(up_rate)).
+ arg(downloadStr).arg(readableFileSize(down_rate)));
+ } else if (up_rate > 0) {
+ setToolTip(QString("%1 %2/s\n").
+ arg(uploadStr).arg(readableFileSize(up_rate)));
+ } else /* down_rate > 0*/ {
+ setToolTip(QString("%1 %2/s\n").
+ arg(downloadStr).arg(readableFileSize(down_rate)));
+ }
+
+ rotate(true);
+}
+
+void SeafileTrayIcon::onMessageClicked()
+{
+ if (is_error_message_) {
+ showSyncErrorsDialog();
+ return;
+ }
+ if (repo_id_.isEmpty())
+ return;
+ LocalRepo repo;
+ if (seafApplet->rpcClient()->getLocalRepo(repo_id_, &repo) != 0 ||
+ !repo.isValid() || repo.worktree_invalid)
+ return;
+
+ DiffReader *reader = new DiffReader(repo, previous_commit_id_, commit_id_);
+ QThreadPool::globalInstance()->start(reader);
+}
+
+void SeafileTrayIcon::checkTrayIconMessageQueue()
+{
+ if (pending_messages_.empty()) {
+ return;
+ }
+
+ qint64 now = QDateTime::currentMSecsSinceEpoch();
+ if (now < next_message_msec_) {
+ return;
+ }
+
+ TrayMessage msg = pending_messages_.dequeue();
+ QSystemTrayIcon::showMessage(msg.title, msg.message, msg.icon, kMessageDisplayTimeMSecs);
+ repo_id_ = msg.repo_id;
+ commit_id_ = msg.commit_id;
+ next_message_msec_ = now + kMessageDisplayTimeMSecs;
+}
+
+
+void SeafileTrayIcon::showSyncErrorsDialog()
+{
+ // Change icon status to daemon up when show sync errors dialog
+ setState(STATE_DAEMON_UP);
+ if (sync_errors_dialog_ == nullptr) {
+ sync_errors_dialog_ = new SyncErrorsDialog;
+ }
+
+ sync_errors_dialog_->updateErrors();
+ sync_errors_dialog_->show();
+ sync_errors_dialog_->raise();
+ sync_errors_dialog_->activateWindow();
+ setSyncErrorStatus(false);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_TRAY_ICON_H
+#define SEAFILE_CLIENT_TRAY_ICON_H
+
+#include <QSystemTrayIcon>
+#include <QHash>
+#include <QQueue>
+
+#include "account.h"
+#include "log-uploader.h"
+
+class ApiError;
+class QAction;
+class QMenu;
+class QMenuBar;
+#if defined(Q_OS_MAC)
+class TrayNotificationManager;
+#endif
+class AboutDialog;
+class SyncErrorsDialog;
+class SeafileTrayIcon : public QSystemTrayIcon {
+ Q_OBJECT
+
+public:
+ explicit SeafileTrayIcon(QObject *parent=0);
+
+ enum TrayState {
+ STATE_DAEMON_UP = 0,
+ STATE_DAEMON_DOWN,
+ STATE_DAEMON_AUTOSYNC_DISABLED,
+ STATE_TRANSFER_1,
+ STATE_TRANSFER_2,
+ STATE_SERVERS_NOT_CONNECTED,
+ STATE_HAVE_UNREAD_MESSAGE,
+ };
+
+ void start();
+
+ TrayState state() const { return state_; }
+ void setState(TrayState state, const QString& tip=QString());
+ void rotate(bool start);
+
+ void reloadTrayIcon();
+
+ void showMessage(const QString& title,
+ const QString& message,
+ const QString& repo_id = QString(),
+ const QString& commit_id = QString(),
+ const QString& previous_commit_id = QString(),
+ MessageIcon icon = Information,
+ int millisecondsTimeoutHint = 10000,
+ bool is_error_message = false);
+
+ void setSyncErrorStatus(bool have_sync_error) {
+ have_sync_errors_= have_sync_error;
+ }
+
+ bool haveSyncError() const { return have_sync_errors_; }
+
+public slots:
+ void showSettingsWindow();
+ void slotSyncErrorUpdate();
+
+private slots:
+ void disableAutoSync();
+ void enableAutoSync();
+ void quitSeafile();
+ void onActivated(QSystemTrayIcon::ActivationReason);
+ void prepareContextMenu();
+ void showMainWindow();
+ void rotateTrayIcon();
+ void refreshTrayIcon();
+ void refreshTrayIconToolTip();
+ void openHelp();
+ void openSeafileFolder();
+ void openLogDirectory();
+ void shellExtFix();
+ void uploadLogDirectory();
+ void about();
+ void checkTrayIconMessageQueue();
+ void clearUploader();
+
+ // only used on windows
+ void onMessageClicked();
+
+ void showSyncErrorsDialog();
+
+private:
+ Q_DISABLE_COPY(SeafileTrayIcon)
+
+ void createActions();
+ void createContextMenu();
+ void createGlobalMenuBar();
+
+ QIcon stateToIcon(TrayState state);
+ QIcon getIcon(const QString& name);
+
+ QMenu *context_menu_;
+ QMenu *help_menu_;
+ QMenu *global_menu_;
+ QMenu *dock_menu_;
+ QMenuBar *global_menubar_;
+
+ // Actions for tray icon menu
+ QAction *enable_auto_sync_action_;
+ QAction *disable_auto_sync_action_;
+ QAction *quit_action_;
+ QAction *show_main_window_action_;
+ QAction *settings_action_;
+ QAction *open_seafile_folder_action_;
+ QAction *open_log_directory_action_;
+ QAction *shellext_fix_action_;
+ QAction *upload_log_directory_action_;
+ QAction *show_sync_errors_action_;
+
+ QAction *about_action_;
+ QAction *open_help_action_;
+
+#if defined(Q_OS_MAC)
+ TrayNotificationManager *tnm;
+#endif
+
+ QTimer *rotate_timer_;
+ QTimer *refresh_timer_;
+ int nth_trayicon_;
+ int rotate_counter_;
+ bool auto_sync_;
+
+ TrayState state_;
+
+ QString repo_id_;
+ QString commit_id_;
+ QString previous_commit_id_;
+ bool is_error_message_;
+
+ QHash<QString, QIcon> icon_cache_;
+
+ struct TrayMessage {
+ QString title;
+ QString message;
+ MessageIcon icon;
+ QString repo_id;
+ QString commit_id;
+ QString previous_commit_id;
+ };
+
+ // Use a queue to gurantee each tray notification message would be
+ // displayed at least several seconds.
+ QQueue<TrayMessage> pending_messages_;
+ qint64 next_message_msec_;
+
+ SyncErrorsDialog *sync_errors_dialog_;
+ AboutDialog *about_dialog_;
+ LogDirUploader *log_dir_uploader_;
+ bool have_sync_errors_ = false;
+};
+
+#endif // SEAFILE_CLIENT_TRAY_ICON_H
--- /dev/null
+#include "two-factor-dialog.h"
+#include "seafile-applet.h"
+
+TwoFactorDialog::TwoFactorDialog(QWidget *parent) :
+ QDialog(parent)
+{
+ setupUi(this);
+ mText->setText(tr("Enter the two factor authentication token"));
+ setWindowTitle(tr("Two Factor Authentication"));
+ setWindowIcon(QIcon(":/images/seafile.png"));
+
+ connect(mSubmit, SIGNAL(clicked()), this, SLOT(doSubmit()));
+}
+
+QString TwoFactorDialog::getText()
+{
+ return mLineEdit->text();
+}
+
+bool TwoFactorDialog::rememberDeviceChecked()
+{
+ return mRememberDevice->isChecked();
+}
+
+void TwoFactorDialog::doSubmit()
+{
+ if (!mLineEdit->text().isEmpty()) {
+ accept();
+ } else {
+ seafApplet->warningBox(tr("Please enter the two factor authentication token"));
+ }
+}
--- /dev/null
+#ifndef TWOFACTORDIALOG_H
+#define TWOFACTORDIALOG_H
+
+#include <QDialog>
+#include "ui_two-factor-dialog.h"
+class TwoFactorDialog : public QDialog,
+ public Ui::TwoFactorDialog
+{
+ Q_OBJECT
+
+public:
+ TwoFactorDialog(QWidget *parent = 0);
+ QString getText();
+ bool rememberDeviceChecked();
+
+private slots:
+ void doSubmit();
+};
+
+#endif // TWOFACTORDIALOG_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "utils/utils.h"
+#include "seafile-applet.h"
+#include "utils/uninstall-helpers.h"
+
+#include "uninstall-helper-dialog.h"
+
+
+UninstallHelperDialog::UninstallHelperDialog(QWidget *parent)
+ : QDialog(parent)
+{
+ setupUi(this);
+ setWindowIcon(QIcon(":/images/seafile.png"));
+ setWindowTitle(tr("Uninstall %1").arg(getBrand()));
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ mText->setText(tr("Do you want to remove the %1 account information?").arg(getBrand()));
+
+ loadQss("qt.css") || loadQss(":/qt.css");
+#if defined(Q_OS_WIN32)
+ loadQss("qt-win.css") || loadQss(":/qt-win.css");
+#elif defined(Q_OS_LINUX)
+ loadQss("qt-linux.css") || loadQss(":/qt-linux.css");
+#else
+ loadQss("qt-mac.css") || loadQss(":/qt-mac.css");
+#endif
+
+ const QRect screen = QApplication::desktop()->screenGeometry();
+ move(screen.center() - this->rect().center());
+
+ connect(mYesBtn, SIGNAL(clicked()),
+ this, SLOT(onYesClicked()));
+
+ connect(mNoBtn, SIGNAL(clicked()),
+ this, SLOT(doExit()));
+}
+
+void UninstallHelperDialog::onYesClicked()
+{
+ mYesBtn->setEnabled(false);
+ mNoBtn->setEnabled(false);
+ mText->setText(tr("Removing account information..."));
+
+ RemoveSeafileDataThread *thread = new RemoveSeafileDataThread;
+ thread->start();
+ connect(thread, SIGNAL(finished()), this, SLOT(doExit()));
+}
+
+void UninstallHelperDialog::doExit()
+{
+ QCoreApplication::exit(0);
+}
+
+bool UninstallHelperDialog::loadQss(const QString& path)
+{
+ QFile file(path);
+ if (!QFileInfo(file).exists()) {
+ return false;
+ }
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ return false;
+ }
+
+ QTextStream input(&file);
+ style_ += "\n";
+ style_ += input.readAll();
+ qApp->setStyleSheet(style_);
+
+ return true;
+}
+
+void RemoveSeafileDataThread::run()
+{
+ QString ccnet_dir;
+ QString seafile_data_dir;
+
+ if (get_ccnet_dir(&ccnet_dir) < 0) {
+ fprintf (stderr, "ccnet dir not found");
+ return;
+ }
+ if (get_seafile_data_dir(ccnet_dir, &seafile_data_dir) < 0) {
+ delete_dir_recursively(ccnet_dir);
+ return;
+ }
+
+ delete_dir_recursively(ccnet_dir);
+ delete_dir_recursively(seafile_data_dir);
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UNINSTALL_HELPER_WINDOW_H
+#define SEAFILE_CLIENT_UNINSTALL_HELPER_WINDOW_H
+
+#include <QThread>
+#include <QDialog>
+#include "ui_uninstall-helper-dialog.h"
+
+
+class UninstallHelperDialog : public QDialog,
+ public Ui::UninstallHelperDialog
+{
+ Q_OBJECT
+public:
+ UninstallHelperDialog(QWidget *parent=0);
+
+private slots:
+ void onYesClicked();
+ void doExit();
+
+private:
+ Q_DISABLE_COPY(UninstallHelperDialog)
+
+ bool loadQss(const QString& path);
+
+ QString style_;
+};
+
+class RemoveSeafileDataThread : public QThread
+{
+ Q_OBJECT
+public:
+ void run();
+};
+
+
+#endif // SEAFILE_CLIENT_UNINSTALL_HELPER_WINDOW_H
--- /dev/null
+#include <QLineEdit>
+#include <QTimer>
+#include <QTreeWidget>
+#include <QTreeWidgetItem>
+#include <QtWidgets>
+
+#include "api/api-error.h"
+#include "api/contact-share-info.h"
+#include "api/requests.h"
+#include "avatar-service.h"
+
+#include "user-name-completer.h"
+
+namespace
+{
+const int kSearchDelayInterval = 150;
+const qint64 kCacheEntryExpireMSecs = 5 * 1000;
+
+enum {
+ USER_COLUMN_AVATAR = 0,
+ USER_COLUMN_NAME,
+ USER_MAX_COLUMN
+};
+
+} // anonymous namespace
+
+SeafileUserNameCompleter::SeafileUserNameCompleter(const Account &account,
+ QLineEdit *parent)
+ : QObject(parent), account_(account), editor_(parent)
+{
+ popup_ = new QTreeWidget;
+ popup_->setWindowFlags(Qt::Popup);
+ popup_->setFocusPolicy(Qt::NoFocus);
+ popup_->setFocusProxy(parent);
+ popup_->setMouseTracking(true);
+
+ popup_->setColumnCount(USER_MAX_COLUMN);
+ popup_->setUniformRowHeights(true);
+ popup_->setRootIsDecorated(false);
+ popup_->setEditTriggers(QTreeWidget::NoEditTriggers);
+ popup_->setSelectionBehavior(QTreeWidget::SelectRows);
+ popup_->setFrameStyle(QFrame::Box | QFrame::Plain);
+ popup_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ popup_->header()->hide();
+
+ popup_->installEventFilter(this);
+
+ connect(popup_,
+ SIGNAL(itemClicked(QTreeWidgetItem *, int)),
+ SLOT(doneCompletion()));
+
+ timer_ = new QTimer(this);
+ timer_->setSingleShot(true);
+ timer_->setInterval(kSearchDelayInterval);
+ connect(timer_, SIGNAL(timeout()), SLOT(autoSuggest()));
+ // Calling start on the timer would effectively stop it & restart again.
+ // Thus we can achieve: only show the completion list when the user has not
+ // typed for a little while, here 150ms.
+ connect(editor_, SIGNAL(textEdited(QString)), timer_, SLOT(start()));
+
+ connect(AvatarService::instance(), SIGNAL(avatarUpdated(const QString&, const QImage&)),
+ this, SLOT(onAvatarUpdated(const QString&, const QImage&)));
+}
+
+SeafileUserNameCompleter::~SeafileUserNameCompleter()
+{
+ popup_->deleteLater();
+}
+
+bool SeafileUserNameCompleter::eventFilter(QObject *obj, QEvent *ev)
+{
+ if (obj != popup_)
+ return false;
+
+ if (ev->type() == QEvent::MouseButtonPress) {
+ popup_->hide();
+ editor_->setFocus();
+ return true;
+ }
+
+ if (ev->type() == QEvent::KeyPress) {
+ bool consumed = false;
+ int key = static_cast<QKeyEvent *>(ev)->key();
+ switch (key) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ doneCompletion();
+ consumed = true;
+ break;
+
+ case Qt::Key_Escape:
+ popup_->hide();
+ editor_->setFocus();
+ consumed = true;
+ break;
+
+ // Pass through the item navigation opeations to the tree widget.
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Home:
+ case Qt::Key_End:
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ break;
+
+ default:
+ editor_->setFocus();
+ editor_->event(ev);
+ popup_->hide();
+ break;
+ }
+
+ return consumed;
+ }
+
+ return false;
+}
+
+void SeafileUserNameCompleter::showCompletion(const QList<SeafileUser> &users, const QString& pattern)
+{
+ if (users.isEmpty())
+ return;
+
+ if (pattern != editor_->text().trimmed()) {
+ // The user has changed the text, so the completions are no longer
+ // useful.
+ // printf("pattern changed from \"%s\" to \"%s\"\n",
+ // pattern.toUtf8().data(),
+ // editor_->text().trimmed().toUtf8().data());
+ return;
+ }
+
+ popup_->setUpdatesEnabled(false);
+ popup_->clear();
+ foreach (const SeafileUser &user, users) {
+ // Do not list the user itself in the completion list.
+ if (user.email == account_.username) {
+ continue;
+ }
+
+ AvatarService *service = AvatarService::instance();
+ QIcon avatar = QPixmap::fromImage(service->getAvatar(user.email));
+
+ QString text =
+ QString("%1 <%2>").arg(user.name).arg(user.getDisplayEmail());
+ QTreeWidgetItem *item;
+ item = new QTreeWidgetItem(popup_);
+ item->setIcon(USER_COLUMN_AVATAR, avatar);
+ item->setText(USER_COLUMN_NAME, text);
+ item->setData(USER_COLUMN_NAME, Qt::UserRole, QVariant::fromValue(user));
+ }
+ popup_->setCurrentItem(popup_->topLevelItem(0));
+ popup_->resizeColumnToContents(USER_COLUMN_AVATAR);
+ popup_->setUpdatesEnabled(true);
+
+ popup_->move(editor_->mapToGlobal(QPoint(0, editor_->height())));
+
+ int w = editor_->width();
+ int maxVisibleItems = 7;
+ int h = (popup_->sizeHintForRow(0) *
+ qMin(maxVisibleItems, popup_->model()->rowCount()) +
+ 3) +
+ 3;
+ h = qMax(h, popup_->minimumHeight());
+ // printf("w = %d, h = %d\n", w, h);
+
+ QPoint pos = editor_->mapToGlobal(QPoint(0, editor_->height()));
+ popup_->setGeometry(pos.x(), pos.y(), w, h);
+
+ popup_->setFocus();
+ if (!popup_->isVisible())
+ popup_->show();
+}
+
+void SeafileUserNameCompleter::doneCompletion()
+{
+ timer_->stop();
+ popup_->hide();
+ editor_->setFocus();
+ QTreeWidgetItem *item = popup_->currentItem();
+ if (item) {
+ SeafileUser user = item->data(USER_COLUMN_NAME, Qt::UserRole).value<SeafileUser>();
+ current_selected_user_ = user;
+ editor_->setText(user.name);
+ QMetaObject::invokeMethod(editor_, "returnPressed");
+ }
+}
+
+void SeafileUserNameCompleter::autoSuggest()
+{
+ current_selected_user_ = SeafileUser();
+ QString pattern = editor_->text().trimmed();
+ if (pattern.isEmpty()) {
+ return;
+ }
+
+ if (cached_completion_users_by_pattern_.contains(pattern) &&
+ cached_completion_users_by_pattern_[pattern].ts +
+ kCacheEntryExpireMSecs >
+ QDateTime::currentMSecsSinceEpoch()) {
+ // printf("cached results for %s\n", pattern.toUtf8().data());
+ showCompletion(
+ cached_completion_users_by_pattern_[pattern].users.toList(), pattern);
+ return;
+ }
+
+ if (in_progress_search_requests_.contains(pattern)) {
+ // printf("already a request for %s\n", pattern.toUtf8().data());
+ return;
+ }
+
+ // printf("request completions for username %s\n", pattern.toUtf8().data());
+ SearchUsersRequest *req = new SearchUsersRequest(account_, pattern);
+ req->setParent(this);
+ connect(req,
+ SIGNAL(success(const QList<SeafileUser> &)),
+ this,
+ SLOT(onSearchUsersSuccess(const QList<SeafileUser> &)));
+ connect(req,
+ SIGNAL(failed(const ApiError &)),
+ this,
+ SLOT(onSearchUsersFailed(const ApiError &)));
+ req->send();
+
+ in_progress_search_requests_.insert(pattern);
+}
+
+void SeafileUserNameCompleter::preventSuggest()
+{
+ timer_->stop();
+}
+
+void SeafileUserNameCompleter::onSearchUsersSuccess(
+ const QList<SeafileUser> &users)
+{
+ SearchUsersRequest *req = qobject_cast<SearchUsersRequest *>(sender());
+ in_progress_search_requests_.remove(req->pattern());
+ req->deleteLater();
+
+ // printf("get %d results for pattern %s\n",
+ // users.size(),
+ // req->pattern().toUtf8().data());
+
+ cached_completion_users_by_pattern_[req->pattern()] = {
+ QSet<SeafileUser>::fromList(users),
+ QDateTime::currentMSecsSinceEpoch()};
+ showCompletion(users, req->pattern());
+}
+
+void SeafileUserNameCompleter::onSearchUsersFailed(const ApiError &error)
+{
+ SearchUsersRequest *req = qobject_cast<SearchUsersRequest *>(sender());
+ in_progress_search_requests_.remove(req->pattern());
+ req->deleteLater();
+}
+
+const SeafileUser& SeafileUserNameCompleter::currentSelectedUser() const
+{
+ return current_selected_user_;
+}
+
+void SeafileUserNameCompleter::onAvatarUpdated(const QString& email,
+ const QImage& avatar)
+{
+ for (int i = 0; i < popup_->topLevelItemCount(); i++) {
+ QTreeWidgetItem* item = popup_->topLevelItem(i);
+ const QString username_email = item->data(USER_COLUMN_NAME, Qt::DisplayRole).toString();
+ if (username_email.contains(email)) {
+ item->setIcon(USER_COLUMN_AVATAR, QPixmap::fromImage(avatar));
+ }
+ }
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UI_USER_NAME_COMPLETER_H
+#define SEAFILE_CLIENT_UI_USER_NAME_COMPLETER_H
+
+#include <QObject>
+
+class QLineEdit;
+class QTimer;
+class QTreeWidget;
+
+struct SeafileUser;
+class ApiError;
+
+#include "account.h"
+#include "api/contact-share-info.h"
+#include "api/requests.h"
+
+class SeafileUserNameCompleter : public QObject
+{
+ Q_OBJECT
+
+public:
+ SeafileUserNameCompleter(const Account& account, QLineEdit *parent = 0);
+ ~SeafileUserNameCompleter();
+ bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE;
+
+ const SeafileUser& currentSelectedUser() const;
+
+private slots:
+ void onSearchUsersSuccess(const QList<SeafileUser>& contacts);
+ void onSearchUsersFailed(const ApiError& error);
+ void doneCompletion();
+ void preventSuggest();
+ void autoSuggest();
+ void showCompletion(const QList<SeafileUser>& users, const QString& pattern);
+ void onAvatarUpdated(const QString& email, const QImage& avatar);
+
+private:
+ Account account_;
+
+ QLineEdit *editor_;
+ QTreeWidget *popup_;
+ QTimer *timer_;
+
+ QSet<QString> in_progress_search_requests_;
+
+ struct CachedUsersEntry {
+ QSet<SeafileUser> users;
+ qint64 ts;
+ };
+ QHash<QString, CachedUsersEntry> cached_completion_users_by_pattern_;
+
+ SeafileUser current_selected_user_;
+};
+
+#endif // SEAFILE_CLIENT_UI_USER_NAME_COMPLETER_H
--- /dev/null
+#include <QHash>
+#include <QHostInfo>
+
+#include "utils.h"
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+#include "api-utils.h"
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kOsName = "windows";
+#elif defined(Q_OS_LINUX)
+const char *kOsName = "linux";
+#else
+const char *kOsName = "mac";
+#endif
+
+} // namespace
+
+QHash<QString, QString>
+getSeafileLoginParams(const QString& computer_name, const QString& prefix)
+{
+
+ QHash<QString, QString> params;
+
+ QString client_version = STRINGIZE(SEAFILE_CLIENT_VERSION);
+ QString device_id = seafApplet->getUniqueClientId();
+ QString computper = computer_name.isEmpty() ? QHostInfo::localHostName()
+ : computer_name;
+
+ params.insert(prefix + "platform", kOsName);
+ params.insert(prefix + "device_id", device_id);
+ params.insert(prefix + "device_name", computer_name);
+ params.insert(prefix + "client_version", client_version);
+ params.insert(prefix + "platform_version", "");
+
+ return params;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_API_UTILS_H_
+#define SEAFILE_CLIENT_API_UTILS_H_
+
+QHash<QString, QString>
+getSeafileLoginParams(const QString& computer_name=QString(),
+ const QString& prefix=QString());
+
+#endif // SEAFILE_CLIENT_API_UTILS_H_
--- /dev/null
+#include <QHash>
+#include <QFileInfo>
+#include <QDir>
+#include <QStringList>
+#include "stl.h"
+
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#endif
+
+#include "file-utils.h"
+
+namespace {
+
+QHash<QString, QString> *types_map = 0;
+
+void init()
+{
+ types_map = new QHash<QString, QString>;
+
+ // Adapted from /etc/mime.types on ubuntu 12.04
+ // TODO: on windows we should read the system registry for a more complete mime types list
+
+ types_map->insert("%", "application/x-trash");
+ types_map->insert("323", "text/h323");
+ types_map->insert("3gp", "video/3gpp");
+ types_map->insert("7z", "application/x-7z-compressed");
+ types_map->insert("a", "application/octet-stream");
+ types_map->insert("abw", "application/x-abiword");
+ types_map->insert("ai", "application/postscript");
+ types_map->insert("aif", "audio/x-aiff");
+ types_map->insert("aifc", "audio/x-aiff");
+ types_map->insert("aiff", "audio/x-aiff");
+ types_map->insert("alc", "chemical/x-alchemy");
+ types_map->insert("amr", "audio/amr");
+ types_map->insert("anx", "application/annodex");
+ types_map->insert("apk", "application/vnd.android.package-archive");
+ types_map->insert("art", "image/x-jg");
+ types_map->insert("asc", "text/plain");
+ types_map->insert("asf", "video/x-ms-asf");
+ types_map->insert("asn", "chemical/x-ncbi-asn1-spec");
+ types_map->insert("aso", "chemical/x-ncbi-asn1-binary");
+ types_map->insert("asx", "video/x-ms-asf");
+ types_map->insert("atom", "application/atom+xml");
+ types_map->insert("atomcat", "application/atomcat+xml");
+ types_map->insert("atomsrv", "application/atomserv+xml");
+ types_map->insert("au", "audio/basic");
+ types_map->insert("avi", "video/x-msvideo");
+ types_map->insert("awb", "audio/amr-wb");
+ types_map->insert("axa", "audio/annodex");
+ types_map->insert("axv", "video/annodex");
+ types_map->insert("b", "chemical/x-molconn-Z");
+ types_map->insert("bak", "application/x-trash");
+ types_map->insert("bat", "application/x-msdos-program");
+ types_map->insert("bcpio", "application/x-bcpio");
+ types_map->insert("bib", "text/x-bibtex");
+ types_map->insert("bin", "application/octet-stream");
+ types_map->insert("bmp", "image/x-ms-bmp");
+ types_map->insert("boo", "text/x-boo");
+ types_map->insert("book", "application/x-maker");
+ types_map->insert("brf", "text/plain");
+ types_map->insert("bsd", "chemical/x-crossfire");
+ types_map->insert("c", "text/x-csrc");
+ types_map->insert("c++", "text/x-c++src");
+ types_map->insert("c3d", "chemical/x-chem3d");
+ types_map->insert("cab", "application/x-cab");
+ types_map->insert("cac", "chemical/x-cache");
+ types_map->insert("cache", "chemical/x-cache");
+ types_map->insert("cap", "application/cap");
+ types_map->insert("cascii", "chemical/x-cactvs-binary");
+ types_map->insert("cat", "application/vnd.ms-pki.seccat");
+ types_map->insert("cbin", "chemical/x-cactvs-binary");
+ types_map->insert("cbr", "application/x-cbr");
+ types_map->insert("cbz", "application/x-cbz");
+ types_map->insert("cc", "text/x-c++src");
+ types_map->insert("cda", "application/x-cdf");
+ types_map->insert("cdf", "application/x-cdf");
+ types_map->insert("cdr", "image/x-coreldraw");
+ types_map->insert("cdt", "image/x-coreldrawtemplate");
+ types_map->insert("cdx", "chemical/x-cdx");
+ types_map->insert("cdy", "application/vnd.cinderella");
+ types_map->insert("cef", "chemical/x-cxf");
+ types_map->insert("cer", "chemical/x-cerius");
+ types_map->insert("chm", "chemical/x-chemdraw");
+ types_map->insert("chrt", "application/x-kchart");
+ types_map->insert("cif", "chemical/x-cif");
+ types_map->insert("class", "application/java-vm");
+ types_map->insert("cls", "text/x-tex");
+ types_map->insert("cmdf", "chemical/x-cmdf");
+ types_map->insert("cml", "chemical/x-cml");
+ types_map->insert("cod", "application/vnd.rim.cod");
+ types_map->insert("com", "application/x-msdos-program");
+ types_map->insert("cpa", "chemical/x-compass");
+ types_map->insert("cpio", "application/x-cpio");
+ types_map->insert("cpp", "text/x-c++src");
+ types_map->insert("cpt", "image/x-corelphotopaint");
+ types_map->insert("cr2", "image/x-canon-cr2");
+ types_map->insert("crl", "application/x-pkcs7-crl");
+ types_map->insert("crt", "application/x-x509-ca-cert");
+ types_map->insert("crw", "image/x-canon-crw");
+ types_map->insert("csd", "audio/csound");
+ types_map->insert("csf", "chemical/x-cache-csf");
+ types_map->insert("csh", "text/x-csh");
+ types_map->insert("csm", "chemical/x-csml");
+ types_map->insert("csml", "chemical/x-csml");
+ types_map->insert("css", "text/css");
+ types_map->insert("csv", "text/csv");
+ types_map->insert("ctab", "chemical/x-cactvs-binary");
+ types_map->insert("ctx", "chemical/x-ctx");
+ types_map->insert("cu", "application/cu-seeme");
+ types_map->insert("cub", "chemical/x-gaussian-cube");
+ types_map->insert("cxf", "chemical/x-cxf");
+ types_map->insert("cxx", "text/x-c++src");
+ types_map->insert("d", "text/x-dsrc");
+ types_map->insert("dat", "application/x-ns-proxy-autoconfig");
+ types_map->insert("davmount", "application/davmount+xml");
+ types_map->insert("dcr", "application/x-director");
+ types_map->insert("deb", "application/x-debian-package");
+ types_map->insert("dif", "video/dv");
+ types_map->insert("diff", "text/x-diff");
+ types_map->insert("dir", "application/x-director");
+ types_map->insert("djv", "image/vnd.djvu");
+ types_map->insert("djvu", "image/vnd.djvu");
+ types_map->insert("dl", "video/dl");
+ types_map->insert("dll", "application/x-msdos-program");
+ types_map->insert("dmg", "application/x-apple-diskimage");
+ types_map->insert("dms", "application/x-dms");
+ types_map->insert("doc", "application/msword");
+ types_map->insert("docm", "application/vnd.ms-word.document.macroEnabled.12");
+ types_map->insert("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ types_map->insert("dot", "application/msword");
+ types_map->insert("dotm", "application/vnd.ms-word.template.macroEnabled.12");
+ types_map->insert("dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template");
+ types_map->insert("dv", "video/dv");
+ types_map->insert("dvi", "application/x-dvi");
+ types_map->insert("dx", "chemical/x-jcamp-dx");
+ types_map->insert("dxr", "application/x-director");
+ types_map->insert("emb", "chemical/x-embl-dl-nucleotide");
+ types_map->insert("embl", "chemical/x-embl-dl-nucleotide");
+ types_map->insert("eml", "message/rfc822");
+ types_map->insert("ent", "chemical/x-pdb");
+ types_map->insert("eps", "application/postscript");
+ types_map->insert("eps2", "application/postscript");
+ types_map->insert("eps3", "application/postscript");
+ types_map->insert("epsf", "application/postscript");
+ types_map->insert("epsi", "application/postscript");
+ types_map->insert("erf", "image/x-epson-erf");
+ types_map->insert("es", "application/ecmascript");
+ types_map->insert("etx", "text/x-setext");
+ types_map->insert("exe", "application/x-msdos-program");
+ types_map->insert("ez", "application/andrew-inset");
+ types_map->insert("fb", "application/x-maker");
+ types_map->insert("fbdoc", "application/x-maker");
+ types_map->insert("fch", "chemical/x-gaussian-checkpoint");
+ types_map->insert("fchk", "chemical/x-gaussian-checkpoint");
+ types_map->insert("fig", "application/x-xfig");
+ types_map->insert("flac", "audio/flac");
+ types_map->insert("fli", "video/fli");
+ types_map->insert("flv", "video/x-flv");
+ types_map->insert("fm", "application/x-maker");
+ types_map->insert("fodg", "application/vnd.oasis.opendocument.graphics-flat-xml");
+ types_map->insert("fodp", "application/vnd.oasis.opendocument.presentation-flat-xml");
+ types_map->insert("fods", "application/vnd.oasis.opendocument.spreadsheet-flat-xml");
+ types_map->insert("fodt", "application/vnd.oasis.opendocument.text-flat-xml");
+ types_map->insert("frame", "application/x-maker");
+ types_map->insert("frm", "application/x-maker");
+ types_map->insert("gal", "chemical/x-gaussian-log");
+ types_map->insert("gam", "chemical/x-gamess-input");
+ types_map->insert("gamin", "chemical/x-gamess-input");
+ types_map->insert("gan", "application/x-ganttproject");
+ types_map->insert("gau", "chemical/x-gaussian-input");
+ types_map->insert("gcd", "text/x-pcs-gcd");
+ types_map->insert("gcf", "application/x-graphing-calculator");
+ types_map->insert("gcg", "chemical/x-gcg8-sequence");
+ types_map->insert("gen", "chemical/x-genbank");
+ types_map->insert("gf", "application/x-tex-gf");
+ types_map->insert("gif", "image/gif");
+ types_map->insert("gjc", "chemical/x-gaussian-input");
+ types_map->insert("gjf", "chemical/x-gaussian-input");
+ types_map->insert("gl", "video/gl");
+ types_map->insert("gnumeric", "application/x-gnumeric");
+ types_map->insert("gpt", "chemical/x-mopac-graph");
+ types_map->insert("gsf", "application/x-font");
+ types_map->insert("gsm", "audio/x-gsm");
+ types_map->insert("gtar", "application/x-gtar");
+ types_map->insert("h", "text/x-chdr");
+ types_map->insert("h++", "text/x-c++hdr");
+ types_map->insert("hdf", "application/x-hdf");
+ types_map->insert("hh", "text/x-c++hdr");
+ types_map->insert("hin", "chemical/x-hin");
+ types_map->insert("hpp", "text/x-c++hdr");
+ types_map->insert("hqx", "application/mac-binhex40");
+ types_map->insert("hs", "text/x-haskell");
+ types_map->insert("hta", "application/hta");
+ types_map->insert("htc", "text/x-component");
+ types_map->insert("htm", "text/html");
+ types_map->insert("html", "text/html");
+ types_map->insert("hxx", "text/x-c++hdr");
+ types_map->insert("ica", "application/x-ica");
+ types_map->insert("ice", "x-conference/x-cooltalk");
+ types_map->insert("ico", "image/x-icon");
+ types_map->insert("ics", "text/calendar");
+ types_map->insert("icz", "text/calendar");
+ types_map->insert("ief", "image/ief");
+ types_map->insert("iges", "model/iges");
+ types_map->insert("igs", "model/iges");
+ types_map->insert("iii", "application/x-iphone");
+ types_map->insert("info", "application/x-info");
+ types_map->insert("inp", "chemical/x-gamess-input");
+ types_map->insert("ins", "application/x-internet-signup");
+ types_map->insert("iso", "application/x-iso9660-image");
+ types_map->insert("isp", "application/x-internet-signup");
+ types_map->insert("ist", "chemical/x-isostar");
+ types_map->insert("istr", "chemical/x-isostar");
+ types_map->insert("jad", "text/vnd.sun.j2me.app-descriptor");
+ types_map->insert("jam", "application/x-jam");
+ types_map->insert("jar", "application/java-archive");
+ types_map->insert("java", "text/x-java");
+ types_map->insert("jdx", "chemical/x-jcamp-dx");
+ types_map->insert("jmz", "application/x-jmol");
+ types_map->insert("jng", "image/x-jng");
+ types_map->insert("jnlp", "application/x-java-jnlp-file");
+ types_map->insert("jpe", "image/jpeg");
+ types_map->insert("jpeg", "image/jpeg");
+ types_map->insert("jpg", "image/jpeg");
+ types_map->insert("js", "application/javascript");
+ types_map->insert("json", "application/json");
+ types_map->insert("kar", "audio/midi");
+ types_map->insert("key", "application/pgp-keys");
+ types_map->insert("kil", "application/x-killustrator");
+ types_map->insert("kin", "chemical/x-kinemage");
+ types_map->insert("kml", "application/vnd.google-earth.kml+xml");
+ types_map->insert("kmz", "application/vnd.google-earth.kmz");
+ types_map->insert("kpr", "application/x-kpresenter");
+ types_map->insert("kpt", "application/x-kpresenter");
+ types_map->insert("ksh", "text/plain");
+ types_map->insert("ksp", "application/x-kspread");
+ types_map->insert("kwd", "application/x-kword");
+ types_map->insert("kwt", "application/x-kword");
+ types_map->insert("latex", "application/x-latex");
+ types_map->insert("lha", "application/x-lha");
+ types_map->insert("lhs", "text/x-literate-haskell");
+ types_map->insert("lin", "application/bbolin");
+ types_map->insert("lsf", "video/x-la-asf");
+ types_map->insert("lsx", "video/x-la-asf");
+ types_map->insert("ltx", "text/x-tex");
+ types_map->insert("lyx", "application/x-lyx");
+ types_map->insert("lzh", "application/x-lzh");
+ types_map->insert("lzx", "application/x-lzx");
+ types_map->insert("m1v", "video/mpeg");
+ types_map->insert("m3g", "application/m3g");
+ types_map->insert("m3u", "audio/x-mpegurl");
+ types_map->insert("m3u8", "application/x-mpegURL");
+ types_map->insert("m4a", "audio/mpeg");
+ types_map->insert("maker", "application/x-maker");
+ types_map->insert("man", "application/x-troff-man");
+ types_map->insert("manifest", "text/cache-manifest");
+ types_map->insert("mcif", "chemical/x-mmcif");
+ types_map->insert("mcm", "chemical/x-macmolecule");
+ types_map->insert("mdb", "application/msaccess");
+ types_map->insert("me", "application/x-troff-me");
+ types_map->insert("mesh", "model/mesh");
+ types_map->insert("mht", "message/rfc822");
+ types_map->insert("mhtml", "message/rfc822");
+ types_map->insert("mid", "audio/midi");
+ types_map->insert("midi", "audio/midi");
+ types_map->insert("mif", "application/x-mif");
+ types_map->insert("mkv", "video/x-matroska");
+ types_map->insert("mm", "application/x-freemind");
+ types_map->insert("mmd", "chemical/x-macromodel-input");
+ types_map->insert("mmf", "application/vnd.smaf");
+ types_map->insert("mml", "text/mathml");
+ types_map->insert("mmod", "chemical/x-macromodel-input");
+ types_map->insert("mng", "video/x-mng");
+ types_map->insert("moc", "text/x-moc");
+ types_map->insert("mol", "chemical/x-mdl-molfile");
+ types_map->insert("mol2", "chemical/x-mol2");
+ types_map->insert("moo", "chemical/x-mopac-out");
+ types_map->insert("mop", "chemical/x-mopac-input");
+ types_map->insert("mopcrt", "chemical/x-mopac-input");
+ types_map->insert("mov", "video/quicktime");
+ types_map->insert("movie", "video/x-sgi-movie");
+ types_map->insert("mp2", "audio/mpeg");
+ types_map->insert("mp3", "audio/mpeg");
+ types_map->insert("mp4", "video/mp4");
+ types_map->insert("mpa", "video/mpeg");
+ types_map->insert("mpc", "chemical/x-mopac-input");
+ types_map->insert("mpe", "video/mpeg");
+ types_map->insert("mpeg", "video/mpeg");
+ types_map->insert("mpega", "audio/mpeg");
+ types_map->insert("mpg", "video/mpeg");
+ types_map->insert("mpga", "audio/mpeg");
+ types_map->insert("mph", "application/x-comsol");
+ types_map->insert("mpv", "video/x-matroska");
+ types_map->insert("ms", "application/x-troff-ms");
+ types_map->insert("msh", "model/mesh");
+ types_map->insert("msi", "application/x-msi");
+ types_map->insert("mvb", "chemical/x-mopac-vib");
+ types_map->insert("mxf", "application/mxf");
+ types_map->insert("mxu", "video/vnd.mpegurl");
+ types_map->insert("nb", "application/mathematica");
+ types_map->insert("nbp", "application/mathematica");
+ types_map->insert("nc", "application/x-netcdf");
+ types_map->insert("nef", "image/x-nikon-nef");
+ types_map->insert("nwc", "application/x-nwc");
+ types_map->insert("nws", "message/rfc822");
+ types_map->insert("o", "application/x-object");
+ types_map->insert("obj", "application/octet-stream");
+ types_map->insert("oda", "application/oda");
+ types_map->insert("odb", "application/vnd.sun.xml.base");
+ types_map->insert("odc", "application/vnd.oasis.opendocument.chart");
+ types_map->insert("odf", "application/vnd.oasis.opendocument.formula");
+ types_map->insert("odg", "application/vnd.oasis.opendocument.graphics");
+ types_map->insert("odi", "application/vnd.oasis.opendocument.image");
+ types_map->insert("odm", "application/vnd.oasis.opendocument.text-master");
+ types_map->insert("odp", "application/vnd.oasis.opendocument.presentation");
+ types_map->insert("ods", "application/vnd.oasis.opendocument.spreadsheet");
+ types_map->insert("odt", "application/vnd.oasis.opendocument.text");
+ types_map->insert("oga", "audio/ogg");
+ types_map->insert("ogg", "audio/ogg");
+ types_map->insert("ogv", "video/ogg");
+ types_map->insert("ogx", "application/ogg");
+ types_map->insert("old", "application/x-trash");
+ types_map->insert("one", "application/onenote");
+ types_map->insert("onepkg", "application/onenote");
+ types_map->insert("onetmp", "application/onenote");
+ types_map->insert("onetoc2", "application/onenote");
+ types_map->insert("orc", "audio/csound");
+ types_map->insert("orf", "image/x-olympus-orf");
+ types_map->insert("otg", "application/vnd.oasis.opendocument.graphics-template");
+ types_map->insert("oth", "application/vnd.oasis.opendocument.text-web");
+ types_map->insert("otp", "application/vnd.oasis.opendocument.presentation-template");
+ types_map->insert("ots", "application/vnd.oasis.opendocument.spreadsheet-template");
+ types_map->insert("ott", "application/vnd.oasis.opendocument.text-template");
+ types_map->insert("oxt", "application/vnd.openofficeorg.extension");
+ types_map->insert("oza", "application/x-oz-application");
+ types_map->insert("p", "text/x-pascal");
+ types_map->insert("p12", "application/x-pkcs12");
+ types_map->insert("p7c", "application/pkcs7-mime");
+ types_map->insert("p7r", "application/x-pkcs7-certreqresp");
+ types_map->insert("pac", "application/x-ns-proxy-autoconfig");
+ types_map->insert("pas", "text/x-pascal");
+ types_map->insert("pat", "image/x-coreldrawpattern");
+ types_map->insert("patch", "text/x-diff");
+ types_map->insert("pbm", "image/x-portable-bitmap");
+ types_map->insert("pcap", "application/cap");
+ types_map->insert("pcf", "application/x-font");
+ types_map->insert("pcf.Z", "application/x-font");
+ types_map->insert("pcx", "image/pcx");
+ types_map->insert("pdb", "chemical/x-pdb");
+ types_map->insert("pdf", "application/pdf");
+ types_map->insert("pfa", "application/x-font");
+ types_map->insert("pfb", "application/x-font");
+ types_map->insert("pfx", "application/x-pkcs12");
+ types_map->insert("pgm", "image/x-portable-graymap");
+ types_map->insert("pgn", "application/x-chess-pgn");
+ types_map->insert("pgp", "application/pgp-signature");
+ types_map->insert("php", "application/x-httpd-php");
+ types_map->insert("php3", "application/x-httpd-php3");
+ types_map->insert("php3p", "application/x-httpd-php3-preprocessed");
+ types_map->insert("php4", "application/x-httpd-php4");
+ types_map->insert("php5", "application/x-httpd-php5");
+ types_map->insert("phps", "application/x-httpd-php-source");
+ types_map->insert("pht", "application/x-httpd-php");
+ types_map->insert("phtml", "application/x-httpd-php");
+ types_map->insert("pk", "application/x-tex-pk");
+ types_map->insert("pl", "text/x-perl");
+ types_map->insert("pls", "audio/x-scpls");
+ types_map->insert("pm", "text/x-perl");
+ types_map->insert("png", "image/png");
+ types_map->insert("pnm", "image/x-portable-anymap");
+ types_map->insert("pot", "text/plain");
+ types_map->insert("potm", "application/vnd.ms-powerpoint.template.macroEnabled.12");
+ types_map->insert("potx", "application/vnd.openxmlformats-officedocument.presentationml.template");
+ types_map->insert("ppa", "application/vnd.ms-powerpoint");
+ types_map->insert("ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12");
+ types_map->insert("ppm", "image/x-portable-pixmap");
+ types_map->insert("pps", "application/vnd.ms-powerpoint");
+ types_map->insert("ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12");
+ types_map->insert("ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow");
+ types_map->insert("ppt", "application/vnd.ms-powerpoint");
+ types_map->insert("pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12");
+ types_map->insert("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
+ types_map->insert("prf", "application/pics-rules");
+ types_map->insert("prt", "chemical/x-ncbi-asn1-ascii");
+ types_map->insert("ps", "application/postscript");
+ types_map->insert("psd", "image/x-photoshop");
+ types_map->insert("pwz", "application/vnd.ms-powerpoint");
+ types_map->insert("py", "text/x-python");
+ types_map->insert("pyc", "application/x-python-code");
+ types_map->insert("pyo", "application/x-python-code");
+ types_map->insert("qgs", "application/x-qgis");
+ types_map->insert("qt", "video/quicktime");
+ types_map->insert("qtl", "application/x-quicktimeplayer");
+ types_map->insert("ra", "audio/x-realaudio");
+ types_map->insert("ram", "audio/x-pn-realaudio");
+ types_map->insert("rar", "application/rar");
+ types_map->insert("ras", "image/x-cmu-raster");
+ types_map->insert("rb", "application/x-ruby");
+ types_map->insert("rd", "chemical/x-mdl-rdfile");
+ types_map->insert("rdf", "application/rdf+xml");
+ types_map->insert("rdp", "application/x-rdp");
+ types_map->insert("rgb", "image/x-rgb");
+ types_map->insert("rhtml", "application/x-httpd-eruby");
+ types_map->insert("rm", "audio/x-pn-realaudio");
+ types_map->insert("roff", "application/x-troff");
+ types_map->insert("ros", "chemical/x-rosdal");
+ types_map->insert("rpm", "application/x-redhat-package-manager");
+ types_map->insert("rss", "application/rss+xml");
+ types_map->insert("rtf", "application/rtf");
+ types_map->insert("rtx", "text/richtext");
+ types_map->insert("rxn", "chemical/x-mdl-rxnfile");
+ types_map->insert("scala", "text/x-scala");
+ types_map->insert("sce", "application/x-scilab");
+ types_map->insert("sci", "application/x-scilab");
+ types_map->insert("sco", "audio/csound");
+ types_map->insert("scr", "application/x-silverlight");
+ types_map->insert("sct", "text/scriptlet");
+ types_map->insert("sd", "chemical/x-mdl-sdfile");
+ types_map->insert("sd2", "audio/x-sd2");
+ types_map->insert("sda", "application/vnd.stardivision.draw");
+ types_map->insert("sdc", "application/vnd.stardivision.calc");
+ types_map->insert("sdd", "application/vnd.stardivision.impress");
+ types_map->insert("sdf", "chemical/x-mdl-sdfile");
+ types_map->insert("sdp", "application/vnd.stardivision.impress");
+ types_map->insert("sds", "application/vnd.stardivision.chart");
+ types_map->insert("sdw", "application/vnd.stardivision.writer");
+ types_map->insert("ser", "application/java-serialized-object");
+ types_map->insert("sfv", "text/x-sfv");
+ types_map->insert("sgf", "application/x-go-sgf");
+ types_map->insert("sgl", "application/vnd.stardivision.writer-global");
+ types_map->insert("sgm", "text/x-sgml");
+ types_map->insert("sgml", "text/x-sgml");
+ types_map->insert("sh", "text/x-sh");
+ types_map->insert("shar", "application/x-shar");
+ types_map->insert("shp", "application/x-qgis");
+ types_map->insert("shtml", "text/html");
+ types_map->insert("shx", "application/x-qgis");
+ types_map->insert("sid", "audio/prs.sid");
+ types_map->insert("sik", "application/x-trash");
+ types_map->insert("silo", "model/mesh");
+ types_map->insert("sis", "application/vnd.symbian.install");
+ types_map->insert("sisx", "x-epoc/x-sisx-app");
+ types_map->insert("sit", "application/x-stuffit");
+ types_map->insert("sitx", "application/x-stuffit");
+ types_map->insert("skd", "application/x-koan");
+ types_map->insert("skm", "application/x-koan");
+ types_map->insert("skp", "application/x-koan");
+ types_map->insert("skt", "application/x-koan");
+ types_map->insert("sldm", "application/vnd.ms-powerpoint.slide.macroEnabled.12");
+ types_map->insert("sldx", "application/vnd.openxmlformats-officedocument.presentationml.slide");
+ types_map->insert("smf", "application/vnd.stardivision.math");
+ types_map->insert("smi", "application/smil");
+ types_map->insert("smil", "application/smil");
+ types_map->insert("snd", "audio/basic");
+ types_map->insert("so", "application/octet-stream");
+ types_map->insert("spc", "chemical/x-galactic-spc");
+ types_map->insert("spl", "application/x-futuresplash");
+ types_map->insert("spx", "audio/ogg");
+ types_map->insert("sql", "application/x-sql");
+ types_map->insert("src", "application/x-wais-source");
+ types_map->insert("stc", "application/vnd.sun.xml.calc.template");
+ types_map->insert("std", "application/vnd.sun.xml.draw.template");
+ types_map->insert("sti", "application/vnd.sun.xml.impress.template");
+ types_map->insert("stl", "application/sla");
+ types_map->insert("stw", "application/vnd.sun.xml.writer.template");
+ types_map->insert("sty", "text/x-tex");
+ types_map->insert("sv4cpio", "application/x-sv4cpio");
+ types_map->insert("sv4crc", "application/x-sv4crc");
+ types_map->insert("svg", "image/svg+xml");
+ types_map->insert("svgz", "image/svg+xml");
+ types_map->insert("sw", "chemical/x-swissprot");
+ types_map->insert("swf", "application/x-shockwave-flash");
+ types_map->insert("swfl", "application/x-shockwave-flash");
+ types_map->insert("sxc", "application/vnd.sun.xml.calc");
+ types_map->insert("sxd", "application/vnd.sun.xml.draw");
+ types_map->insert("sxg", "application/vnd.sun.xml.writer.global");
+ types_map->insert("sxi", "application/vnd.sun.xml.impress");
+ types_map->insert("sxm", "application/vnd.sun.xml.math");
+ types_map->insert("sxw", "application/vnd.sun.xml.writer");
+ types_map->insert("t", "application/x-troff");
+ types_map->insert("tar", "application/x-tar");
+ types_map->insert("taz", "application/x-gtar-compressed");
+ types_map->insert("tcl", "text/x-tcl");
+ types_map->insert("tex", "text/x-tex");
+ types_map->insert("texi", "application/x-texinfo");
+ types_map->insert("texinfo", "application/x-texinfo");
+ types_map->insert("text", "text/plain");
+ types_map->insert("tgf", "chemical/x-mdl-tgf");
+ types_map->insert("tgz", "application/x-gtar-compressed");
+ types_map->insert("thmx", "application/vnd.ms-officetheme");
+ types_map->insert("tif", "image/tiff");
+ types_map->insert("tiff", "image/tiff");
+ types_map->insert("tk", "text/x-tcl");
+ types_map->insert("tm", "text/texmacs");
+ types_map->insert("torrent", "application/x-bittorrent");
+ types_map->insert("tr", "application/x-troff");
+ types_map->insert("ts", "video/MP2T");
+ types_map->insert("tsp", "application/dsptype");
+ types_map->insert("tsv", "text/tab-separated-values");
+ types_map->insert("txt", "text/plain");
+ types_map->insert("udeb", "application/x-debian-package");
+ types_map->insert("uls", "text/iuls");
+ types_map->insert("ustar", "application/x-ustar");
+ types_map->insert("val", "chemical/x-ncbi-asn1-binary");
+ types_map->insert("vcd", "application/x-cdlink");
+ types_map->insert("vcf", "text/x-vcard");
+ types_map->insert("vcs", "text/x-vcalendar");
+ types_map->insert("vmd", "chemical/x-vmd");
+ types_map->insert("vms", "chemical/x-vamas-iso14976");
+ types_map->insert("vor", "application/vnd.stardivision.writer");
+ types_map->insert("vrm", "x-world/x-vrml");
+ types_map->insert("vrml", "x-world/x-vrml");
+ types_map->insert("vsd", "application/vnd.visio");
+ types_map->insert("wad", "application/x-doom");
+ types_map->insert("wav", "audio/x-wav");
+ types_map->insert("wax", "audio/x-ms-wax");
+ types_map->insert("wbmp", "image/vnd.wap.wbmp");
+ types_map->insert("wbxml", "application/vnd.wap.wbxml");
+ types_map->insert("webm", "video/webm");
+ types_map->insert("wiz", "application/msword");
+ types_map->insert("wk", "application/x-123");
+ types_map->insert("wm", "video/x-ms-wm");
+ types_map->insert("wma", "audio/x-ms-wma");
+ types_map->insert("wmd", "application/x-ms-wmd");
+ types_map->insert("wml", "text/vnd.wap.wml");
+ types_map->insert("wmlc", "application/vnd.wap.wmlc");
+ types_map->insert("wmls", "text/vnd.wap.wmlscript");
+ types_map->insert("wmlsc", "application/vnd.wap.wmlscriptc");
+ types_map->insert("wmv", "video/x-ms-wmv");
+ types_map->insert("wmx", "video/x-ms-wmx");
+ types_map->insert("wmz", "application/x-ms-wmz");
+ types_map->insert("wp5", "application/vnd.wordperfect5.1");
+ types_map->insert("wpd", "application/vnd.wordperfect");
+ types_map->insert("wrl", "x-world/x-vrml");
+ types_map->insert("wsc", "text/scriptlet");
+ types_map->insert("wsdl", "application/xml");
+ types_map->insert("wvx", "video/x-ms-wvx");
+ types_map->insert("wz", "application/x-wingz");
+ types_map->insert("x3d", "model/x3d+xml");
+ types_map->insert("x3db", "model/x3d+binary");
+ types_map->insert("x3dv", "model/x3d+vrml");
+ types_map->insert("xbm", "image/x-xbitmap");
+ types_map->insert("xcf", "application/x-xcf");
+ types_map->insert("xht", "application/xhtml+xml");
+ types_map->insert("xhtml", "application/xhtml+xml");
+ types_map->insert("xlam", "application/vnd.ms-excel.addin.macroEnabled.12");
+ types_map->insert("xlb", "application/vnd.ms-excel");
+ types_map->insert("xls", "application/vnd.ms-excel");
+ types_map->insert("xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12");
+ types_map->insert("xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12");
+ types_map->insert("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+ types_map->insert("xlt", "application/vnd.ms-excel");
+ types_map->insert("xltm", "application/vnd.ms-excel.template.macroEnabled.12");
+ types_map->insert("xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template");
+ types_map->insert("xml", "application/xml");
+ types_map->insert("xpdl", "application/xml");
+ types_map->insert("xpi", "application/x-xpinstall");
+ types_map->insert("xpm", "image/x-xpixmap");
+ types_map->insert("xsd", "application/xml");
+ types_map->insert("xsl", "application/xml");
+ types_map->insert("xspf", "application/xspf+xml");
+ types_map->insert("xtel", "chemical/x-xtel");
+ types_map->insert("xul", "application/vnd.mozilla.xul+xml");
+ types_map->insert("xwd", "image/x-xwindowdump");
+ types_map->insert("xyz", "chemical/x-xyz");
+ types_map->insert("zip", "application/zip");
+ types_map->insert("zmt", "chemical/x-mopac-input");
+ types_map->insert("~", "application/x-trash");
+}
+
+QString splitPath(const QString& path, int *pos)
+{
+ if (path.isEmpty()) {
+ return "";
+ }
+
+ QString p = QDir::fromNativeSeparators(path);
+ while (p.endsWith('/') && p.size() > 1) {
+ p = p.left(p.size() - 1);
+ }
+ if (p.size() == 1) {
+ return p;
+ }
+
+ *pos = p.lastIndexOf("/");
+ return p;
+}
+
+
+} // namespace
+
+QString mimeTypeFromFileName(const QString& fileName)
+{
+ if (types_map == 0) {
+ init();
+ }
+
+ QString suffix = QFileInfo(fileName).suffix().toLower();
+
+ return types_map->value(suffix);
+}
+
+QString readableNameForFolder(bool readonly)
+{
+ return readonly ? QObject::tr("Readonly Folder") : QObject::tr("Folder");
+}
+
+QString readableNameForFile(const QString& fileName)
+{
+ QString mimetype = mimeTypeFromFileName(fileName);
+
+ if (mimetype.isEmpty()) {
+ return QObject::tr("Document");
+ }
+
+ if (mimetype == "application/pdf") {
+ return QObject::tr("PDF Document");
+ } else if (mimetype.startsWith("image")) {
+ return QObject::tr("Image File");
+ } else if (mimetype.startsWith("text")) {
+ return QObject::tr("Text Document");
+ } else if (mimetype.startsWith("audio")) {
+ return QObject::tr("Audio File");
+ } else if (mimetype.startsWith("video")) {
+ return QObject::tr("Video File");
+ } else if (mimetype.contains("msword") || mimetype.contains("ms-word")) {
+ return QObject::tr("Word Document");
+ } else if (mimetype.contains("mspowerpoint") || mimetype.contains("ms-powerpoint")) {
+ return QObject::tr("PowerPoint Document");
+ } else if (mimetype.contains("msexcel") || mimetype.contains("ms-excel")) {
+ return QObject::tr("Excel Document");
+ } else if (mimetype.contains("openxmlformats-officedocument")) {
+ // see http://stackoverflow.com/questions/4212861/what-is-a-correct-mime-type-for-docx-pptx-etc
+ if (mimetype.contains("wordprocessingml")) {
+ return QObject::tr("Word Document");
+ } else if (mimetype.contains("spreadsheetml")) {
+ return QObject::tr("Excel Document");
+ } else if (mimetype.contains("presentationml")) {
+ return QObject::tr("PowerPoint Document");
+ }
+ // } else if (mimetype.contains("application")) {
+ // return "binary";
+ }
+
+ return QObject::tr("Document");
+}
+
+QString iconPrefixFromFileName(const QString& fileName)
+{
+ QString mimetype = mimeTypeFromFileName(fileName);
+
+ if (mimetype.isEmpty()) {
+ return "";
+ }
+
+ if (mimetype == "application/pdf") {
+ return "pdf";
+ } else if (mimetype.startsWith("image")) {
+ return "image";
+ } else if (mimetype.startsWith("text")) {
+ return "text";
+ } else if (mimetype.startsWith("audio")) {
+ return "audio";
+ } else if (mimetype.startsWith("video")) {
+ return "video";
+ } else if (mimetype.contains("msword") || mimetype.contains("ms-word")) {
+ return "ms_word";
+ } else if (mimetype.contains("mspowerpoint") || mimetype.contains("ms-powerpoint")) {
+ return "ms_ppt";
+ } else if (mimetype.contains("msexcel") || mimetype.contains("ms-excel")) {
+ return "ms_excel";
+ } else if (mimetype.contains("openxmlformats-officedocument")) {
+ // see http://stackoverflow.com/questions/4212861/what-is-a-correct-mime-type-for-docx-pptx-etc
+ if (mimetype.contains("wordprocessingml")) {
+ return "ms_word";
+ } else if (mimetype.contains("spreadsheetml")) {
+ return "ms_excel";
+ } else if (mimetype.contains("presentationml")) {
+ return "ms_ppt";
+ }
+ // } else if (mimetype.contains("application")) {
+ // return "binary";
+ } else if (mimetype.contains("7z") || mimetype.contains("rar") ||
+ mimetype.contains("zip") || mimetype.startsWith("application/x-tar")) {
+ return "zip";
+ }
+
+ return "";
+}
+
+
+QString getIconByFileName(const QString& fileName)
+{
+ QString icon = iconPrefixFromFileName(fileName);
+
+ if (icon.isEmpty()) {
+ icon = "unknown";
+ }
+
+ return QString(":/images/files/file_%1.png").arg(icon);
+}
+
+QString getIconByFolder()
+{
+ return QString(":/images/files/file_folder.png");
+}
+
+QString getIconByFileNameV2(const QString& fileName)
+{
+ QString icon = iconPrefixFromFileName(fileName);
+
+ // Use doc icons for text files
+ if (icon == "text") {
+ icon = "ms_word";
+ }
+
+ return QString(":/images/files_v2/file_%1.png").arg(icon.isEmpty() ? "unknown" : icon);
+}
+
+
+QString pathJoin(const QString& a,
+ const QString& b)
+{
+ QStringList list(b);
+ return pathJoin(a, list);
+}
+
+
+QString pathJoin(const QString& a,
+ const QString& b,
+ const QString& c)
+{
+ QStringList list;
+ list << b << c;
+ return pathJoin(a, list);
+}
+
+QString pathJoin(const QString& a,
+ const QString& b,
+ const QString& c,
+ const QString& d)
+{
+ QStringList list;
+ list << b << c << d;
+ return pathJoin(a, list);
+}
+
+QString pathJoin(const QString& a, const QStringList& rest)
+{
+ QString result = a;
+ foreach (const QString& b, rest) {
+ bool resultEndsWithSlash = result.endsWith("/");
+ bool bStartWithSlash = b.startsWith("/");
+ if (resultEndsWithSlash && bStartWithSlash) {
+ result.append(b.right(b.size() - 1));
+ } else if (resultEndsWithSlash || bStartWithSlash) {
+ result.append(b);
+ } else {
+ result.append("/" + b);
+ }
+ }
+
+ return result;
+}
+
+bool createDirIfNotExists(const QString& path)
+{
+ QDir parent_dir = getParentPath(path);
+ return parent_dir.mkpath(getBaseName(path));
+}
+
+QString getParentPath(const QString& path)
+{
+ int pos;
+ QString p = splitPath(path, &pos);
+ if (p.size() <= 1) {
+ return p;
+ }
+
+ if (pos == -1)
+ return "";
+ if (pos == 0)
+ return "/";
+ return p.left(pos);
+}
+
+QString getBaseName(const QString& path)
+{
+ int pos;
+ QString p = splitPath(path, &pos);
+ if (p.size() <= 1) {
+ return p;
+ }
+
+ if (pos == -1) {
+ return p;
+ }
+ return p.mid(pos + 1);
+}
+
+QString expandVars(const QString& origin)
+{
+#ifdef Q_OS_WIN32
+ // expand environment strings
+ QString retval;
+ std::wstring worigin = origin.toStdWString();
+ utils::WBufferArray expanded;
+ expanded.resize(MAX_PATH);
+ DWORD expanded_size = ExpandEnvironmentStringsW(&worigin[0], &expanded[0], MAX_PATH);
+ if (expanded_size > 0) {
+ expanded.resize(expanded_size);
+ if (expanded_size > MAX_PATH)
+ expanded_size = ExpandEnvironmentStringsW(&worigin[0], &expanded[0], expanded_size);
+ }
+ if (expanded_size > 0 && expanded_size == expanded.size()) {
+ retval = QString::fromWCharArray(&expanded[0], expanded_size);
+ // workaround with a bug
+ retval = QString::fromUtf8(retval.toUtf8());
+ } else {
+ retval = origin;
+ }
+#else
+ // TODO implement it
+ QString retval = origin;
+#endif
+ return retval;
+}
+
+QString expandUser(const QString& origin)
+{
+ if (origin.startsWith("~")) {
+ QChar seperator = QDir::separator();
+ int pos = 1;
+ while (pos < origin.size() && origin[pos] != seperator)
+ ++pos;
+ QString homepath;
+ if (pos == 1)
+ homepath = QDir::homePath();
+ else
+ homepath = QFileInfo(QDir::homePath()).dir().filePath(origin.mid(1, pos - 1));
+ return pathJoin(homepath, origin.right(origin.size() - pos));
+ }
+ return origin;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_FILE_UTILS_H_
+#define SEAFILE_CLIENT_FILE_UTILS_H_
+
+#include <QString>
+class QStringList;
+
+QString mimeTypeFromFileName(const QString& fileName);
+QString iconPrefixFromFileName(const QString& fileName);
+
+QString getIconByFolder();
+
+QString getIconByFileName(const QString& fileName);
+QString getIconByFileNameV2(const QString& fileName);
+
+QString readableNameForFolder(bool readonly = false);
+QString readableNameForFile(const QString& fileName);
+
+QString getParentPath(const QString& path);
+QString getBaseName(const QString& path);
+
+QString pathJoin(const QString& a, const QString& b);
+QString pathJoin(const QString& a, const QString& b, const QString& c);
+QString pathJoin(const QString& a, const QString& b, const QString& c, const QString& d);
+QString pathJoin(const QString& a, const QStringList& rest);
+
+QString expandVars(const QString& origin);
+QString expandUser(const QString& origin);
+
+bool createDirIfNotExists(const QString& path);
+
+
+#endif // SEAFILE_CLIENT_FILE_UTILS_H_
--- /dev/null
+#include <jansson.h>
+#include "json-utils.h"
+
+Json::Json(const json_t *root)
+{
+ json_ = root;
+}
+
+QString Json::getString(const char *key) const
+{
+ if (!json_) {
+ return QString();
+ }
+ return QString::fromUtf8(json_string_value(json_object_get(json_, key)));
+}
+
+qint64 Json::getLong(const char *key) const
+{
+ if (!json_) {
+ return 0;
+ }
+ return json_integer_value(json_object_get(json_, key));
+}
+
+bool Json::getBool(const char *key) const
+{
+ if (!json_) {
+ return false;
+ }
+
+ json_t *value = json_object_get(json_, key);
+ if (json_is_false(value))
+ return false;
+ return json_is_true(value) || json_integer_value(value);
+}
+
+Json Json::getObject(const char *key) const
+{
+ if (!json_) {
+ return Json();
+ }
+
+ json_t *object = json_object_get(json_, key);
+ if (json_is_object(object))
+ return Json(object);
+ return Json();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_JSON_UTILS_H
+
+#include <jansson.h>
+#include <QString>
+
+// A convenient class to access jasson `json_t` struct
+class Json {
+public:
+ Json(const json_t *root = 0);
+
+ QString getString(const char *name) const;
+ qint64 getLong(const char *name) const;
+ bool getBool(const char *name) const;
+ Json getObject(const char *name) const;
+
+private:
+ const json_t *json_;
+};
+
+#endif // SEAFILE_CLIENT_UTILS_JSON_UTILS_H
--- /dev/null
+#include <errno.h>
+#include <time.h>
+#include <glib/gstdio.h>
+
+#include "log.h"
+
+static FILE *logfp;
+
+static GLogLevelFlags applet_log_level;
+
+static int
+checkdir_with_mkdir (const char *dir)
+{
+#if defined(_WIN32)
+ int ret;
+ char *path = g_strdup(dir);
+ char *p = (char *)path + strlen(path) - 1;
+ while (*p == '\\' || *p == '/') *p-- = '\0';
+ ret = g_mkdir_with_parents(path, 0755);
+ g_free (path);
+ return ret;
+#else
+ return g_mkdir_with_parents(dir, 0755);
+#endif
+}
+
+static void
+applet_log (const gchar *log_domain, GLogLevelFlags log_level,
+ const gchar *message, gpointer user_data)
+{
+#define BUFSIZE 1024
+ if (log_level > applet_log_level || message == NULL)
+ return;
+
+ if (log_level & G_LOG_FLAG_FATAL)
+ fputs (message, stderr);
+
+ time_t t;
+ struct tm *tm;
+ char buf[BUFSIZE];
+ size_t len;
+
+ t = time(NULL);
+ tm = localtime(&t);
+ len = strftime (buf, BUFSIZE, "[%x %X]", tm);
+ g_return_if_fail (len < BUFSIZE);
+ fputs (buf, logfp);
+ fputs (message, logfp);
+
+ if (strlen(message) > 0 && message[strlen(message) - 1] != '\n') {
+ fputs("\n", logfp);
+ }
+ fflush (logfp);
+#undef BUFSIZE
+}
+
+static void
+delete_large_log_file(const char* file)
+{
+ GStatBuf log_file_stat_buf;
+ if (g_stat(file, &log_file_stat_buf) != 0) {
+ // Do not warn if errno=2 (file not exist), because during
+ // first run of the client the log files may not be created
+ // yet.
+ if (errno != 2) {
+ g_warning ("Get log file %s stat failed errno=%d.", file, errno);
+ }
+ return;
+ }
+
+ const int delete_threshold = 300 * 1000 * 1000;
+ if (log_file_stat_buf.st_size <= delete_threshold) {
+ return;
+ } else {
+ const char* backup_file_name_postfix = "-old";
+ GString *backup_file = g_string_new(file);
+ g_string_insert(backup_file, backup_file->len - 4, backup_file_name_postfix);
+ // 4 is length of log file postfix ".log"
+ // rename log file "***.log" to "***-old.log"
+ char file_name[4096] = {0};
+ memcpy(file_name, backup_file->str, backup_file->len);
+ if (backup_file) {
+ g_string_free(backup_file, TRUE);
+ }
+
+ if (g_file_test(file_name, G_FILE_TEST_EXISTS)) {
+ if (g_remove(file_name) != 0) {
+ g_warning ("Delete old log file %s failed errno=%d.", file_name, errno);
+ return;
+ } else {
+ g_warning ("Deleted old log file %s.", file_name);
+ }
+ }
+
+ if (g_rename(file, file_name) == 0) {
+ g_warning ("Renamed %s to backup file %s.", file, file_name);
+ return;
+ } else {
+ g_warning ("Rename %s to backup file failed errno=%d.", file, errno);
+ return;
+ }
+ }
+}
+
+int
+applet_log_init (const char *ccnet_dir)
+{
+ char *logdir = g_build_filename (ccnet_dir, "logs", NULL);
+ char *applet_log_file = g_build_filename(logdir, "applet.log", NULL);
+ char *seafile_log_file = g_build_filename(logdir, "seafile.log", NULL);
+
+ if (checkdir_with_mkdir (logdir) < 0) {
+ g_free (logdir);
+ return -1;
+ }
+
+ g_free (logdir);
+
+ delete_large_log_file(applet_log_file);
+ delete_large_log_file(seafile_log_file);
+
+ /* record all log message */
+ applet_log_level = G_LOG_LEVEL_DEBUG;
+
+ if ((logfp = g_fopen (applet_log_file, "a+")) == NULL) {
+ g_warning ("Open file %s failed errno=%d\n", applet_log_file, errno);
+ g_free (applet_log_file);
+ return -1;
+ }
+
+ g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
+ | G_LOG_FLAG_RECURSION, applet_log, NULL);
+
+ g_log_set_handler ("Ccnet", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
+ | G_LOG_FLAG_RECURSION, applet_log, NULL);
+
+ g_free (applet_log_file);
+
+ return 0;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_LOG_H
+#define SEAFILE_CLIENT_UTILS_LOG_H
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+G_BEGIN_DECLS
+
+int applet_log_init (const char *ccnet_dir);
+
+G_END_DECLS
+
+#endif // SEAFILE_CLIENT_UTILS_LOG_H
--- /dev/null
+#include <QtGlobal>
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QtWidgets>
+#else
+#include <QtGui>
+#endif
+
+#include "paint-utils.h"
+
+QString fitTextToWidth(const QString& text, const QFont& font, int width)
+{
+ static QString ELLIPSISES = "...";
+
+ QFontMetrics qfm(font);
+ QSize size = qfm.size(0, text);
+ if (size.width() <= width)
+ return text; // it fits, so just display it
+
+ // doesn't fit, so we need to truncate and add ellipses
+ QSize sizeElippses = qfm.size(0, ELLIPSISES); // we need to cut short enough to add these
+ QString s = text;
+ while (s.length() > 0) // never cut shorter than this...
+ {
+ int len = s.length();
+ s = text.left(len-1);
+ size = qfm.size(0, s);
+ if (size.width() <= (width - sizeElippses.width()))
+ break; // we are finally short enough
+ }
+
+ return (s + ELLIPSISES);
+}
+
+QFont zoomFont(const QFont& font_in, double ratio)
+{
+ QFont font(font_in);
+
+ if (font.pointSize() > 0) {
+ font.setPointSize((int)(font.pointSize() * ratio));
+ } else {
+ font.setPixelSize((int)(font.pixelSize() * ratio));
+ }
+
+ return font;
+}
+
+QFont changeFontSize(const QFont& font_in, int size)
+{
+ QFont font(font_in);
+
+ font.setPixelSize(size);
+
+ // if (font.pointSize() > 0) {
+ // font.setPointSize(size);
+ // } else {
+ // font.setPixelSize(size);
+ // }
+
+ return font;
+}
+
+int textWidthInFont(const QString text, const QFont& font)
+{
+ QFontMetrics qfm(font);
+ QSize size = qfm.size(0, text);
+
+ return size.width();
+}
+
+int textHeightInFont(const QString text, const QFont& font)
+{
+ QFontMetrics qfm(font);
+ QSize size = qfm.size(Qt::TextSingleLine, text);
+
+ return size.height();
+}
+
+// it might change when screen moves
+// QIcon::addFile will add a "@2x" file if it exists.
+double globalDevicePixelRatio()
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ return qApp->devicePixelRatio();
+#else
+ return 1.0;
+#endif
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_PAINT_UTILS_H_
+#define SEAFILE_CLIENT_PAINT_UTILS_H_
+
+#include <QFont>
+#include "utils-mac.h"
+#include <QIcon>
+
+QString fitTextToWidth(const QString& text, const QFont& font, int width);
+
+QFont zoomFont(const QFont& font_in, double ratio);
+
+QFont changeFontSize(const QFont& font_in, int size);
+
+int textWidthInFont(const QString text, const QFont& font);
+
+int textHeightInFont(const QString text, const QFont& font);
+
+double globalDevicePixelRatio();
+
+#endif // SEAFILE_CLIENT_PAINT_UTILS_H_
--- /dev/null
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glib.h>
+
+#include "process.h"
+#if !defined(PATH_MAX)
+#define PATH_MAX 512
+#endif
+namespace {
+const int kBUFFSIZE = 4096;
+}
+
+static int
+find_process_in_dirent(struct dirent *dir, const char *process_name)
+{
+ char path[PATH_MAX];
+ /* first construct a path like /proc/123/exe */
+ if (snprintf (path, PATH_MAX, "/proc/%s/exe", dir->d_name) < 0) {
+ return -1;
+ }
+
+ char buf[kBUFFSIZE];
+ /* get the full path of exe */
+ ssize_t l = readlink(path, buf, kBUFFSIZE - 1);
+
+ if (l < 0)
+ return -1;
+ buf[l] = '\0';
+
+ /* get the base name of exe */
+ char *base = g_path_get_basename(buf);
+ int ret = strcmp(base, process_name);
+ g_free(base);
+
+ if (ret == 0)
+ return atoi(dir->d_name);
+ else
+ return -1;
+}
+
+/* read the /proc fs to determine whether some process is running */
+int process_is_running (const char *process_name)
+{
+ DIR *proc_dir = opendir("/proc");
+ if (!proc_dir) {
+ fprintf (stderr, "failed to open /proc/ dir\n");
+ return FALSE;
+ }
+
+ struct dirent *subdir = NULL;
+ while ((subdir = readdir(proc_dir))) {
+ char first = subdir->d_name[0];
+ /* /proc/[1-9][0-9]* */
+ if (first > '9' || first < '1')
+ continue;
+ int pid = find_process_in_dirent(subdir, process_name);
+ if (pid > 0) {
+ closedir(proc_dir);
+ return TRUE;
+ }
+ }
+
+ closedir(proc_dir);
+ return FALSE;
+}
+
+void shutdown_process (const char *name)
+{
+ DIR *proc_dir = opendir("/proc");
+ if (!proc_dir) {
+ fprintf (stderr, "failed to open /proc/ dir\n");
+ return;
+ }
+
+ struct dirent *subdir = NULL;
+ pid_t current_pid = getpid();
+ while ((subdir = readdir(proc_dir))) {
+ char first = subdir->d_name[0];
+ /* /proc/[1-9][0-9]* */
+ if (first > '9' || first < '1')
+ continue;
+ int pid = find_process_in_dirent(subdir, name);
+ // don't kill itself!
+ if (pid > 0 && pid != current_pid) {
+ kill (pid, SIGKILL);
+ }
+ }
+
+ closedir(proc_dir);
+}
+
+int count_process(const char *process_name)
+{
+ int count = 0;
+ DIR *proc_dir = opendir("/proc");
+ if (!proc_dir) {
+ g_warning ("failed to open /proc/ :%s\n", strerror(errno));
+ return FALSE;
+ }
+
+ struct dirent *subdir = NULL;
+ while ((subdir = readdir(proc_dir))) {
+ char first = subdir->d_name[0];
+ /* /proc/[1-9][0-9]* */
+ if (first > '9' || first < '1')
+ continue;
+ if (find_process_in_dirent(subdir, process_name) > 0) {
+ count++;
+ }
+ }
+
+ closedir (proc_dir);
+ return count;
+}
+
+int count_process(const char *name, uint64_t *pid)
+{
+ return count_process(name);
+}
--- /dev/null
+#include "process.h"
+
+#include <sys/sysctl.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glib.h>
+
+typedef struct kinfo_proc kinfo_proc;
+
+static int GetBSDProcessList (kinfo_proc **procList, size_t *procCount)
+{
+ int err;
+ kinfo_proc * result;
+ bool done;
+ static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+ // Declaring name as const requires us to cast it when passing it to
+ // sysctl because the prototype doesn't include the const modifier.
+ size_t length;
+
+ assert ( procList != NULL);
+ assert (*procList == NULL);
+ assert (procCount != NULL);
+
+ *procCount = 0;
+
+ // We start by calling sysctl with result == NULL and length == 0.
+ // That will succeed, and set length to the appropriate length.
+ // We then allocate a buffer of that size and call sysctl again
+ // with that buffer. If that succeeds, we're done. If that fails
+ // with ENOMEM, we have to throw away our buffer and loop. Note
+ // that the loop causes use to call sysctl with NULL again; this
+ // is necessary because the ENOMEM failure case sets length to
+ // the amount of data returned, not the amount of data that
+ // could have been returned.
+
+ result = NULL;
+ done = false;
+ do {
+ assert (result == NULL);
+ // Call sysctl with a NULL buffer.
+
+ length = 0;
+ err = sysctl ((int *) name, (sizeof(name) / sizeof(*name)) - 1,
+ NULL, &length,
+ NULL, 0);
+ if (err == -1) {
+ err = errno;
+ }
+
+ // Allocate an appropriately sized buffer based on the results
+ // from the previous call.
+
+ if (err == 0) {
+ result = (kinfo_proc *)malloc (length);
+ if (result == NULL) {
+ err = ENOMEM;
+ }
+ }
+
+ // Call sysctl again with the new buffer. If we get an ENOMEM
+ // error, toss away our buffer and start again.
+
+ if (err == 0) {
+ err = sysctl ((int *) name, (sizeof(name) / sizeof(*name)) - 1,
+ result, &length,
+ NULL, 0);
+ if (err == -1) {
+ err = errno;
+ }
+ if (err == 0) {
+ done = true;
+ } else if (err == ENOMEM) {
+ assert(result != NULL);
+ free (result);
+ result = NULL;
+ err = 0;
+ }
+ }
+ } while (err == 0 && ! done);
+
+ // Clean up and establish post conditions.
+
+ if (err != 0 && result != NULL) {
+ free (result);
+ result = NULL;
+ }
+ *procList = result;
+ if (err == 0) {
+ *procCount = length / sizeof(kinfo_proc);
+ }
+
+ assert ( (err == 0) == (*procList != NULL) );
+
+ return err;
+}
+
+static int getBSDProcessPid (const char *name, int except_pid)
+{
+ int pid = 0;
+ struct kinfo_proc *mylist = NULL;
+ size_t mycount = 0;
+ GetBSDProcessList (&mylist, &mycount);
+ for (size_t k = 0; k < mycount; k++) {
+ kinfo_proc *proc = &mylist[k];
+ if (proc->kp_proc.p_pid != except_pid
+ && strcmp (proc->kp_proc.p_comm, name) == 0
+ && proc->kp_eproc.e_pcred.p_ruid == getuid()){
+ pid = proc->kp_proc.p_pid;
+ break;
+ }
+ }
+ free (mylist);
+ return pid;
+}
+
+int process_is_running (const char *name)
+{
+ int pid = getBSDProcessPid (name, getpid ());
+ if (pid)
+ return true;
+ return false;
+}
+
+
+void shutdown_process (const char *name)
+{
+ struct kinfo_proc *mylist = NULL;
+ size_t mycount = 0;
+ pid_t current_pid = getpid();
+ GetBSDProcessList (&mylist, &mycount);
+ for (size_t k = 0; k < mycount; k++) {
+ kinfo_proc *proc = &mylist[k];
+ if (strcmp (proc->kp_proc.p_comm, name) == 0 &&
+ proc->kp_proc.p_pid != current_pid &&
+ proc->kp_eproc.e_pcred.p_ruid == getuid()) {
+ // printf ("seaf-daemon pid = %d\n", proc->kp_proc.p_pid);
+ kill (proc->kp_proc.p_pid, SIGKILL);
+ }
+ }
+ free (mylist);
+}
+
+int count_process(const char *process_name)
+{
+ int count = 0;
+ struct kinfo_proc *mylist = NULL;
+ size_t mycount = 0;
+ GetBSDProcessList (&mylist, &mycount);
+ for (size_t k = 0; k < mycount; k++) {
+ kinfo_proc *proc = &mylist[k];
+ if (strcmp (proc->kp_proc.p_comm, process_name) == 0
+ && proc->kp_eproc.e_pcred.p_ruid == getuid()){
+ count++;
+ }
+ }
+ free (mylist);
+ return count;
+}
+
+int count_process(const char *name, uint64_t *pid)
+{
+ return count_process(name);
+}
--- /dev/null
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+#include <windows.h>
+#include <psapi.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string>
+
+#include <QList>
+
+#include "process.h"
+
+namespace {
+
+/// always ignore current process
+HANDLE
+get_process_handle (const char *process_name_in)
+{
+ char name[256];
+ if (strstr(process_name_in, ".exe")) {
+ snprintf (name, sizeof(name), "%s", process_name_in);
+ } else {
+ snprintf (name, sizeof(name), "%s.exe", process_name_in);
+ }
+
+ DWORD aProcesses[1024], cbNeeded, cProcesses;
+
+ if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))
+ return NULL;
+
+ /* Calculate how many process identifiers were returned. */
+ cProcesses = cbNeeded / sizeof(DWORD);
+
+ HANDLE hProcess;
+ DWORD hCurrentProcessId = GetCurrentProcessId();
+ unsigned int i;
+ DWORD length;
+
+ for (i = 0; i < cProcesses; i++) {
+ if(aProcesses[i] == 0 || aProcesses[i] == hCurrentProcessId)
+ continue;
+ hProcess = OpenProcess (PROCESS_QUERY_INFORMATION |
+ PROCESS_TERMINATE |
+ PROCESS_VM_READ |
+ SYNCHRONIZE , FALSE, aProcesses[i]);
+ if (!hProcess)
+ continue;
+
+ char process_name[4096] = {0};
+
+ // The GetProcessImageFileName function returns the path in device form, rather than drive letters
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683196%28v=vs.85%29.aspx
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683217%28v=vs.85%29.aspx
+ if (!(length = GetProcessImageFileName(hProcess, process_name, sizeof(process_name)))) {
+ CloseHandle(hProcess);
+ continue;
+ }
+ char *basename = strrchr(process_name, '\\');
+ length -= (basename - process_name);
+
+ // if basename doesn't start with `\` or not mached
+ if (*basename != '\\' ||
+ strncasecmp(name, ++basename, length) != 0) {
+ CloseHandle(hProcess);
+ continue;
+ }
+
+ return hProcess;
+ }
+ /* Not found */
+ return NULL;
+}
+
+int
+win32_kill_process (const char *process_name)
+{
+ HANDLE proc_handle = get_process_handle(process_name);
+
+ if (proc_handle) {
+ TerminateProcess(proc_handle, 0);
+ CloseHandle(proc_handle);
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+
+} // namespace
+
+int
+process_is_running (const char *process_name)
+{
+ HANDLE proc_handle = get_process_handle(process_name);
+
+ if (proc_handle) {
+ CloseHandle(proc_handle);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+void shutdown_process (const char *name)
+{
+ while (win32_kill_process(name) >= 0) ;
+}
+
+// Return the number of processes with the given executable name, and also
+// return the list of pids of them (except the current process, if it mathces)
+static int count_process_internal (const char *process_name_in, QList<uint64_t> *pids)
+{
+ char name[MAX_PATH];
+ DWORD aProcesses[1024], cbNeeded, cProcesses;
+ HANDLE hProcess;
+ DWORD length;
+ int count = 0;
+ DWORD i;
+ DWORD hCurrentProcessId = GetCurrentProcessId();
+
+ if (strstr(process_name_in, ".exe")) {
+ snprintf (name, sizeof(name), "%s", process_name_in);
+ } else {
+ snprintf (name, sizeof(name), "%s.exe", process_name_in);
+ }
+
+ if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
+ return 0;
+ }
+
+ /* Calculate how many process identifiers were returned. */
+ cProcesses = cbNeeded / sizeof(DWORD);
+
+ for (i = 0; i < cProcesses; i++) {
+ if(aProcesses[i] == 0)
+ continue;
+ hProcess = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
+ if (!hProcess) {
+ continue;
+ }
+
+ char process_name[4096] = {0};
+ if (!(length = GetProcessImageFileName(hProcess, process_name, sizeof(process_name)))) {
+ CloseHandle(hProcess);
+ continue;
+ }
+ char *basename = strrchr(process_name, '\\');
+ length -= (basename - process_name);
+
+ // if basename doesn't start with `\` or not mached
+ if (*basename != '\\' ||
+ strncasecmp(name, ++basename, length) != 0) {
+ CloseHandle(hProcess);
+ continue;
+ }
+
+ if (pids && aProcesses[i] != hCurrentProcessId) {
+ pids->append(aProcesses[i]);
+ }
+ count++;
+ CloseHandle(hProcess);
+ }
+
+ return count;
+}
+
+int count_process (const char *process_name_in) {
+ return count_process_internal(process_name_in, nullptr);
+}
+
+int count_process(const char *name, uint64_t *pid)
+{
+ QList<uint64_t> pids;
+ int ret = count_process_internal(name, &pids);
+ if (pid && !pids.isEmpty()) {
+ *pid = pids[0];
+ }
+ return ret;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_PROCESS_H
+#define SEAFILE_CLIENT_UTILS_PROCESS_H
+
+#include <stdint.h>
+
+// process related functions
+int process_is_running (const char *process_name);
+
+void shutdown_process (const char *name);
+
+// Return the number of processes whose executable name is `name`.
+int count_process(const char *name);
+
+// Same as count_process(name), but also return the pid of the first matched
+// non-self process.
+int count_process(const char *name, uint64_t *pid);
+
+#endif // SEAFILE_CLIENT_UTILS_PROCESS_H
--- /dev/null
+#include <windows.h>
+#include <shlwapi.h>
+#include <vector>
+
+#include "utils/stl.h"
+#include "utils/utils.h"
+
+
+#include "registry.h"
+
+namespace {
+
+LONG openKey(HKEY root, const QString& path, HKEY *p_key, REGSAM samDesired = KEY_ALL_ACCESS)
+{
+ LONG result;
+ result = RegOpenKeyExW(root,
+ path.toStdWString().c_str(),
+ 0L,
+ samDesired,
+ p_key);
+
+ return result;
+}
+
+QString softwareSeafile()
+{
+ return QString("SOFTWARE\\%1").arg(getBrand());
+}
+
+} // namespace
+
+RegElement::RegElement(const HKEY& root, const QString& path,
+ const QString& name, const QString& value, bool expand)
+ : root_(root),
+ path_(path),
+ name_(name),
+ string_value_(value),
+ dword_value_(0),
+ type_(expand ? REG_EXPAND_SZ : REG_SZ)
+{
+}
+
+RegElement::RegElement(const HKEY& root, const QString& path,
+ const QString& name, DWORD value)
+ : root_(root),
+ path_(path),
+ name_(name),
+ string_value_(""),
+ dword_value_(value),
+ type_(REG_DWORD)
+{
+}
+
+int RegElement::openParentKey(HKEY *pKey)
+{
+ DWORD disp;
+ HRESULT result;
+
+ result = RegCreateKeyExW (root_,
+ path_.toStdWString().c_str(),
+ 0, NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE | KEY_WOW64_64KEY,
+ NULL,
+ pKey,
+ &disp);
+
+ if (result != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int RegElement::add()
+{
+ HKEY parent_key;
+ DWORD value_len;
+ LONG result;
+
+ if (openParentKey(&parent_key) < 0) {
+ return -1;
+ }
+
+ if (type_ == REG_SZ || type_ == REG_EXPAND_SZ) {
+ // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms724923(v=vs.85).aspx
+ value_len = sizeof(wchar_t) * (string_value_.toStdWString().length() + 1);
+ result = RegSetValueExW (parent_key,
+ name_.toStdWString().c_str(),
+ 0, REG_SZ,
+ (const BYTE *)(string_value_.toStdWString().c_str()),
+ value_len);
+ } else {
+ value_len = sizeof(dword_value_);
+ result = RegSetValueExW (parent_key,
+ name_.toStdWString().c_str(),
+ 0, REG_DWORD,
+ (const BYTE *)&dword_value_,
+ value_len);
+ }
+
+ if (result != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int RegElement::removeRegKey(HKEY root, const QString& path, const QString& subkey)
+{
+ HKEY hKey;
+ LONG result = RegOpenKeyExW(root,
+ path.toStdWString().c_str(),
+ 0L,
+ KEY_ALL_ACCESS,
+ &hKey);
+
+ if (result != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ result = SHDeleteKeyW(hKey, subkey.toStdWString().c_str());
+ if (result != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ return 0;
+}
+
+bool RegElement::exists()
+{
+ HKEY parent_key;
+ LONG result = openKey(root_, path_, &parent_key, KEY_READ);
+ if (result != ERROR_SUCCESS) {
+ return false;
+ }
+
+ result = RegQueryValueExW (parent_key,
+ name_.toStdWString().c_str(),
+ NULL, /* reserved */
+ NULL, /* output type */
+ NULL, /* output data */
+ NULL); /* output length */
+
+ RegCloseKey(parent_key);
+ if (result != ERROR_SUCCESS) {
+ return false;
+ }
+
+ return true;
+}
+
+void RegElement::read()
+{
+ string_value_.clear();
+ dword_value_ = 0;
+ HKEY parent_key;
+ LONG result = openKey(root_, path_, &parent_key, KEY_READ);
+ if (result != ERROR_SUCCESS) {
+ return;
+ }
+ const std::wstring std_name = name_.toStdWString();
+
+ DWORD len;
+ // get value size
+ result = RegQueryValueExW (parent_key,
+ std_name.c_str(),
+ NULL, /* reserved */
+ &type_, /* output type */
+ NULL, /* output data */
+ &len); /* output length */
+ if (result != ERROR_SUCCESS) {
+ RegCloseKey(parent_key);
+ return;
+ }
+ // get value
+#ifndef UTILS_CXX11_MODE
+ std::vector<wchar_t> buf;
+#else
+ utils::WBufferArray buf;
+#endif
+ buf.resize(len);
+ result = RegQueryValueExW (parent_key,
+ std_name.c_str(),
+ NULL, /* reserved */
+ &type_, /* output type */
+ (LPBYTE)&buf[0], /* output data */
+ &len); /* output length */
+ buf.resize(len);
+ if (result != ERROR_SUCCESS) {
+ RegCloseKey(parent_key);
+ return;
+ }
+
+ switch (type_) {
+ case REG_EXPAND_SZ:
+ case REG_SZ:
+ {
+ // expand environment strings
+ wchar_t expanded_buf[MAX_PATH];
+ DWORD size = ExpandEnvironmentStringsW(&buf[0], expanded_buf, MAX_PATH);
+ if (size == 0 || size > MAX_PATH)
+ string_value_ = QString::fromWCharArray(&buf[0], buf.size());
+ else
+ string_value_ = QString::fromWCharArray(expanded_buf, size);
+ }
+ break;
+ case REG_NONE:
+ case REG_BINARY:
+ string_value_ = QString::fromWCharArray(&buf[0], buf.size() / 2);
+ break;
+ case REG_DWORD_BIG_ENDIAN:
+ case REG_DWORD:
+ if (buf.size() != sizeof(int))
+ return;
+ memcpy((char*)&dword_value_, buf.data(), sizeof(int));
+ break;
+ case REG_QWORD: {
+ if (buf.size() != sizeof(int))
+ return;
+ qint64 value;
+ memcpy((char*)&value, buf.data(), sizeof(int));
+ dword_value_ = (int)value;
+ break;
+ }
+ case REG_MULTI_SZ:
+ default:
+ break;
+ }
+
+ RegCloseKey(parent_key);
+
+ // workaround with a bug
+ string_value_ = QString::fromUtf8(string_value_.toUtf8());
+
+ return;
+}
+
+void RegElement::remove()
+{
+ HKEY parent_key;
+ LONG result = openKey(root_, path_, &parent_key, KEY_ALL_ACCESS);
+ if (result != ERROR_SUCCESS) {
+ return;
+ }
+ result = RegDeleteValueW (parent_key, name_.toStdWString().c_str());
+ RegCloseKey(parent_key);
+}
+
+QVariant RegElement::value() const
+{
+ if (type_ == REG_SZ || type_ == REG_EXPAND_SZ
+ || type_ == REG_NONE || type_ == REG_BINARY) {
+ return string_value_;
+ } else {
+ return int(dword_value_);
+ }
+}
+
+int RegElement::getIntValue(HKEY root,
+ const QString& path,
+ const QString& name,
+ bool *exists,
+ int default_val)
+{
+ RegElement reg(root, path, name, "");
+ if (!reg.exists()) {
+ if (exists) {
+ *exists = false;
+ }
+ return default_val;
+ }
+ if (exists) {
+ *exists = true;
+ }
+ reg.read();
+
+ if (!reg.stringValue().isEmpty())
+ return reg.stringValue().toInt();
+
+ return reg.dwordValue();
+}
+
+int RegElement::getPreconfigureIntValue(const QString& name)
+{
+ bool exists;
+ int ret = getIntValue(
+ HKEY_CURRENT_USER, softwareSeafile(), name, &exists);
+ if (exists) {
+ return ret;
+ }
+
+ return RegElement::getIntValue(
+ HKEY_LOCAL_MACHINE, softwareSeafile(), name);
+}
+
+QString RegElement::getStringValue(HKEY root,
+ const QString& path,
+ const QString& name,
+ bool *exists,
+ QString default_val)
+{
+ RegElement reg(root, path, name, "");
+ if (!reg.exists()) {
+ if (exists) {
+ *exists = false;
+ }
+ return default_val;
+ }
+ if (exists) {
+ *exists = true;
+ }
+ reg.read();
+ return reg.stringValue();
+}
+
+QString RegElement::getPreconfigureStringValue(const QString& name)
+{
+ bool exists;
+ QString ret = getStringValue(
+ HKEY_CURRENT_USER, softwareSeafile(), name, &exists);
+ if (exists) {
+ return ret;
+ }
+
+ return RegElement::getStringValue(
+ HKEY_LOCAL_MACHINE, softwareSeafile(), name);
+}
+
+QVariant RegElement::getPreconfigureValue(const QString& name)
+{
+ QVariant v = getValue(HKEY_CURRENT_USER, softwareSeafile(), name);
+ return v.isNull() ? getValue(HKEY_LOCAL_MACHINE, softwareSeafile(), name) : v;
+}
+
+QVariant RegElement::getValue(HKEY root,
+ const QString& path,
+ const QString& name)
+{
+ RegElement reg(root, path, name, "");
+ if (!reg.exists()) {
+ return QVariant();
+ }
+ reg.read();
+
+ return reg.value();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_REGISTRY_H
+#define SEAFILE_CLIENT_UTILS_REGISTRY_H
+
+#include <QString>
+#include <QVariant>
+#include <windows.h>
+
+
+#ifndef KEY_WOW64_64KEY
+#define KEY_WOW64_64KEY 0x0100
+#endif
+
+#ifndef KEY_WOW64_32KEY
+#define KEY_WOW64_32KEY 0x0200
+#endif
+
+/**
+ * Windows Registry Element
+ */
+class RegElement {
+public:
+ static void removeRegKey(const QString& key);
+
+ RegElement(const HKEY& root,
+ const QString& path,
+ const QString& name,
+ const QString& value,
+ bool expand=false);
+
+ RegElement(const HKEY& root,
+ const QString& path,
+ const QString& name,
+ DWORD value);
+
+ int add();
+ void read();
+ void remove();
+ bool exists();
+
+ const HKEY& root() const { return root_; }
+ const QString& path() const { return path_; }
+ const QString& name() const { return name_; }
+ const QString& stringValue() const { return string_value_; }
+ DWORD dwordValue() const { return dword_value_; }
+ QVariant value() const;
+
+public:
+ static int removeRegKey(HKEY root, const QString& path, const QString& subkey);
+
+ static int getIntValue(HKEY root, const QString& path, const QString& name, bool *exists=NULL, int default_val=0);
+ static QString getStringValue(HKEY root, const QString& path, const QString& name, bool *exists=NULL, QString default_val=QString());
+ static int getPreconfigureIntValue(const QString& name);
+ static QString getPreconfigureStringValue(const QString& name);
+
+ static QVariant getPreconfigureValue(const QString& name);
+ static QVariant getValue(HKEY root, const QString& path, const QString& name);
+
+private:
+ int openParentKey(HKEY *pKey);
+
+ HKEY root_;
+ QString path_;
+ QString name_;
+ QString string_value_;
+ DWORD dword_value_;
+ DWORD type_;
+};
+
+#endif // SEAFILE_CLIENT_UTILS_REGISTRY_H
--- /dev/null
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/err.h>
+
+#include <glib.h>
+#include <cstring>
+
+#include "rsa.h"
+#include "utils.h"
+
+namespace {
+
+/* Forward compatibility functions if libssl < 1.1.0. */
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+ /* If the fields n and e in r are NULL, the corresponding input
+ * parameters MUST be non-NULL for n and e. d may be
+ * left NULL (in case only the public key is used).
+ */
+ if ((r->n == NULL && n == NULL)
+ || (r->e == NULL && e == NULL))
+ return 0;
+ if (n != NULL) {
+ BN_free(r->n);
+ r->n = n;
+ }
+ if (e != NULL) {
+ BN_free(r->e);
+ r->e = e;
+ }
+ if (d != NULL) {
+ BN_free(r->d);
+ r->d = d;
+ }
+ return 1;
+}
+
+void RSA_get0_key(const RSA *r,
+ const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+ if (n != NULL)
+ *n = r->n;
+ if (e != NULL)
+ *e = r->e;
+ if (d != NULL)
+ *d = r->d;
+}
+
+#endif
+
+int calculate_sha1 (unsigned char *sha1, const char *msg)
+{
+ SHA_CTX c;
+
+ SHA1_Init(&c);
+ SHA1_Update(&c, msg, strlen(msg));
+ SHA1_Final(sha1, &c);
+ return 0;
+}
+
+void
+rawdata_to_hex (const unsigned char *rawdata, char *hex_str, int n_bytes)
+{
+ static const char hex[] = "0123456789abcdef";
+ int i;
+
+ for (i = 0; i < n_bytes; i++) {
+ unsigned int val = *rawdata++;
+ *hex_str++ = hex[val >> 4];
+ *hex_str++ = hex[val & 0xf];
+ }
+ *hex_str = '\0';
+}
+
+#define sha1_to_hex(sha1, hex) rawdata_to_hex((sha1), (hex), 20)
+
+GString* public_key_to_gstring(const RSA *rsa)
+{
+ GString *buf = g_string_new(NULL);
+ unsigned char *temp;
+ char *coded;
+ const BIGNUM *n, *e;
+
+ RSA_get0_key (rsa, &n, &e, NULL);
+ gsize len = BN_num_bytes(n);
+ temp = (unsigned char *)malloc(len);
+ BN_bn2bin(n, temp);
+ coded = g_base64_encode(temp, len);
+ g_string_append (buf, coded);
+ g_string_append_c (buf, ' ');
+ g_free(coded);
+
+ len = BN_num_bytes(e);
+ temp = (unsigned char*)realloc(temp, len);
+ BN_bn2bin(e, temp);
+ coded = g_base64_encode(temp, len);
+ g_string_append (buf, coded);
+ g_free(coded);
+
+ free(temp);
+
+ return buf;
+}
+
+/*
+RSA* public_key_from_string(char *str)
+{
+ char *p;
+ unsigned char *num;
+ gsize len;
+ if (!str)
+ return NULL;
+
+ if ( !(p = strchr(str, ' ')) )
+ return NULL;
+ *p = '\0';
+
+ RSA *key = RSA_new();
+
+ num = g_base64_decode(str, &len);
+ key->n = BN_bin2bn(num, len, NULL);
+ if (!key->n)
+ goto err;
+ g_free(num);
+
+ num = g_base64_decode(p+1, &len);
+ key->e = BN_bin2bn(num, len, NULL);
+ if (!key->e)
+ goto err;
+ g_free(num);
+
+ *p = ' ';
+ return key;
+err:
+ *p = ' ';
+ RSA_free (key);
+ g_free(num);
+ return NULL;
+}
+*/
+
+} // namespace
+
+
+RSA*
+private_key_to_pub(RSA *priv)
+{
+ RSA *pub = RSA_new();
+ const BIGNUM *n, *e;
+
+ RSA_get0_key (priv, &n, &e, NULL);
+ RSA_set0_key (pub, BN_dup(n), BN_dup(e), NULL);
+
+ return pub;
+}
+
+
+char *
+id_from_pubkey (RSA *pubkey)
+{
+ GString *buf;
+ unsigned char sha1[20];
+ char *id = (char *)g_malloc(41);
+
+ buf = public_key_to_gstring (pubkey);
+ calculate_sha1 (sha1, buf->str);
+ sha1_to_hex (sha1, id);
+ g_string_free (buf, TRUE);
+
+ return id;
+}
+
+RSA *
+generate_private_key(int bits)
+{
+ RSA *priv = RSA_new ();
+ BIGNUM *e = BN_new ();
+
+ BN_set_word (e, 35);
+ RSA_generate_key_ex (priv, bits, e, NULL);
+
+ BN_free (e);
+ return priv;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef SEAFILE_CLIENT_RSA_H
+#define SEAFILE_CLIENT_RSA_H
+
+#include <openssl/rsa.h>
+
+RSA* private_key_to_pub(RSA *priv);
+
+RSA* generate_private_key(int bits);
+
+char *id_from_pubkey (RSA *pubkey);
+
+#endif
--- /dev/null
+#include "seafile-error.h"
+#include <seafile/seafile-error.h>
+
+QString
+translateSyncErrorCode(const int error_code)
+{
+ QString error_str;
+ switch (error_code) {
+ case SYNC_ERROR_ID_FILE_LOCKED_BY_APP:
+ error_str = QObject::tr("File is locked by another application");
+ break;
+ case SYNC_ERROR_ID_FOLDER_LOCKED_BY_APP:
+ error_str = QObject::tr("Folder is locked by another application");
+ break;
+ case SYNC_ERROR_ID_FILE_LOCKED:
+ error_str = QObject::tr("File is locked by another user");
+ break;
+ case SYNC_ERROR_ID_INVALID_PATH:
+ error_str = QObject::tr("Path is invalid");
+ break;
+ case SYNC_ERROR_ID_INDEX_ERROR:
+ error_str = QObject::tr("Error when indexing");
+ break;
+ case SYNC_ERROR_ID_PATH_END_SPACE_PERIOD:
+ error_str = QObject::tr("Path ends with space or period character");
+ break;
+ case SYNC_ERROR_ID_PATH_INVALID_CHARACTER:
+ error_str = QObject::tr("Path contains invalid characters like '|' or ':'");
+ break;
+ case SYNC_ERROR_ID_FOLDER_PERM_DENIED:
+ error_str = QObject::tr("Update to file denied by folder permission setting");
+ break;
+ case SYNC_ERROR_ID_PERM_NOT_SYNCABLE:
+ error_str = QObject::tr("No permission to sync this folder");
+ break;
+ case SYNC_ERROR_ID_UPDATE_TO_READ_ONLY_REPO:
+ error_str = QObject::tr("Created or updated a file in a non-writable library or folder");
+ break;
+ case SYNC_ERROR_ID_ACCESS_DENIED:
+ error_str = QObject::tr("Permission denied on server");
+ break;
+ case SYNC_ERROR_ID_NO_WRITE_PERMISSION:
+ error_str = QObject::tr("Do not have write permission to the library");
+ break;
+ case SYNC_ERROR_ID_QUOTA_FULL:
+ error_str = QObject::tr("Storage quota full");
+ break;
+ case SYNC_ERROR_ID_NETWORK:
+ error_str = QObject::tr("Network error");
+ break;
+ case SYNC_ERROR_ID_RESOLVE_PROXY:
+ error_str = QObject::tr("Cannot resolve proxy address");
+ break;
+ case SYNC_ERROR_ID_RESOLVE_HOST:
+ error_str = QObject::tr("Cannot resolve server address");
+ break;
+ case SYNC_ERROR_ID_CONNECT:
+ error_str = QObject::tr("Cannot connect to server");
+ break;
+ case SYNC_ERROR_ID_SSL:
+ error_str = QObject::tr("Failed to establish secure connection. Please check server SSL certificate");
+ break;
+ case SYNC_ERROR_ID_TX:
+ error_str = QObject::tr("Data transfer was interrupted. Please check network or firewall");
+ break;
+ case SYNC_ERROR_ID_TX_TIMEOUT:
+ error_str = QObject::tr("Data transfer timed out. Please check network or firewall");
+ break;
+ case SYNC_ERROR_ID_UNHANDLED_REDIRECT:
+ error_str = QObject::tr("Unhandled http redirect from server. Please check server cofiguration");
+ break;
+ case SYNC_ERROR_ID_SERVER:
+ error_str = QObject::tr("Server error");
+ break;
+ case SYNC_ERROR_ID_LOCAL_DATA_CORRUPT:
+ error_str = QObject::tr("Internal data corrupt on the client. Please try to resync the library");
+ break;
+ case SYNC_ERROR_ID_WRITE_LOCAL_DATA:
+ error_str = QObject::tr("Failed to write data on the client. Please check disk space or folder permissions");
+ break;
+ case SYNC_ERROR_ID_SERVER_REPO_DELETED:
+ error_str = QObject::tr("Library deleted on server");
+ break;
+ case SYNC_ERROR_ID_SERVER_REPO_CORRUPT:
+ error_str = QObject::tr("Library damaged on server");
+ break;
+ case SYNC_ERROR_ID_NOT_ENOUGH_MEMORY:
+ error_str = QObject::tr("Not enough memory");
+ break;
+ case SYNC_ERROR_ID_CONFLICT:
+ error_str = QObject::tr("Concurrent updates to file. File is saved as conflict file");
+ break;
+ case SYNC_ERROR_ID_GENERAL_ERROR:
+ error_str = QObject::tr("Unknown error");
+ break;
+ case SYNC_ERROR_ID_REMOVE_UNCOMMITTED_FOLDER:
+ error_str = QObject::tr("A folder that may contain not-yet-uploaded files is moved to seafile-recycle-bin folder.");
+ break;
+ default:
+ qWarning("Unknown sync error");
+ }
+ return error_str;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_SEAFILE_ERROR_H
+#define SEAFILE_CLIENT_SEAFILE_ERROR_H
+
+#include <QObject>
+#include <QString>
+
+QString
+translateSyncErrorCode(const int error_code);
+
+#endif //SEAFILE_CLIENT_SEAFILE_ERROR_H
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_SINGLETON_H
+#define SEAFILE_CLIENT_UTILS_SINGLETON_H
+
+/**
+ * This macro helps conveniently define singleton classes. Usage:
+ *
+ * // foo.h
+ * #include "utils/singleton.h"
+ * class Foo {
+ * SINGLETON_DEFINE(Foo)
+ * private:
+ * Foo()
+ * ...
+ * }
+
+ * // foo.cpp
+ * #include "foo.h"
+ * SINGLETON_IMPL(Foo)
+*/
+
+#define SINGLETON_DEFINE(CLASS) \
+ public: \
+ static CLASS *instance(); \
+ private: \
+ static CLASS *singleton_; \
+
+#define SINGLETON_IMPL(CLASS) \
+ CLASS* CLASS::singleton_; \
+ CLASS* CLASS::instance() { \
+ if (singleton_ == NULL) { \
+ static CLASS instance; \
+ singleton_ = &instance; \
+ } \
+ return singleton_; \
+ }
+
+#endif // SEAFILE_CLIENT_UTILS_SINGLETON_H
--- /dev/null
+#include "stl.h"
+
+namespace utils {
+
+template class BasicBufferArray<char>;
+template class BasicBufferArray<wchar_t>;
+
+template <>
+inline void swap(BasicBufferArray<char> &LHS,
+ BasicBufferArray<char> &RHS) UTILS_CXX11_NOEXCEPT;
+
+template <>
+inline void swap(BasicBufferArray<wchar_t> &LHS,
+ BasicBufferArray<wchar_t> &RHS) UTILS_CXX11_NOEXCEPT;
+
+} // namespace utils
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_STL_H_
+#define SEAFILE_CLIENT_UTILS_STL_H_
+
+#include <utility>
+#include <cassert>
+#include <string>
+#include <cstring>
+#include <cwchar>
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L)
+#define UTILS_CXX11_MODE
+#define UTILS_CXX11_DELETE = delete
+#define UTILS_CXX11_NOEXCEPT noexcept
+#else
+#define UTILS_CXX11_DELETE
+#define UTILS_CXX11_NOEXCEPT
+#endif
+
+namespace utils {
+template <typename T = char> class BasicBufferArray {
+ typedef T char_type;
+ char_type *data_;
+ size_t size_;
+ size_t capacity_;
+
+ BasicBufferArray(const BasicBufferArray &buffer) UTILS_CXX11_DELETE;
+ BasicBufferArray &
+ operator=(const BasicBufferArray &buffer) UTILS_CXX11_DELETE;
+
+ public:
+ void swap(BasicBufferArray &RHS) UTILS_CXX11_NOEXCEPT {
+ std::swap(data_, RHS.data_);
+ std::swap(size_, RHS.size_);
+ std::swap(capacity_, RHS.capacity_);
+ }
+#ifdef UTILS_CXX11_MODE
+ BasicBufferArray(BasicBufferArray &&RHS) UTILS_CXX11_NOEXCEPT
+ : data_(RHS.data_),
+ size_(RHS.size_),
+ capacity_(RHS.capacity_) {
+ RHS.data_ = NULL;
+ RHS.size_ = 0;
+ RHS.capacity_ = 0;
+ }
+ BasicBufferArray &operator=(BasicBufferArray &&RHS) UTILS_CXX11_NOEXCEPT {
+ std::swap(data_, RHS.data_);
+ std::swap(size_, RHS.size_);
+ std::swap(capacity_, RHS.capacity_);
+ return *this;
+ }
+#endif // UTILS_CXX11_MODE
+
+ ~BasicBufferArray() {
+ if (capacity_ && data_)
+ delete[] data_;
+ }
+ BasicBufferArray() : data_(NULL), size_(0), capacity_(0){};
+ BasicBufferArray(const char_type *buffer) {
+ const char_type *end = buffer;
+ while (*end++ != '\0')
+ ;
+ capacity_ = size_ = end - buffer;
+
+ data_ = new char_type[size_];
+ assert(data_ != NULL);
+ memcpy(data_, buffer, size_ * sizeof(char_type));
+ }
+ BasicBufferArray(const char_type *buffer, size_t size) {
+ data_ = new char_type[size];
+ assert(data_ != NULL);
+ capacity_ = size_ = size;
+ memcpy(data_, buffer, size * sizeof(char_type));
+ }
+ BasicBufferArray(const std::basic_string<char_type> &string) {
+ if (string.size() == 0) {
+ data_ = NULL;
+ capacity_ = size_ = 0;
+ return;
+ }
+ capacity_ = size_ = string.size() + 1;
+ data_ = new char_type[size_];
+ assert(data_ != NULL);
+ memcpy(data_, string.data(), size_ * sizeof(char_type));
+ data_[size_ - 1] = '\0';
+ }
+
+ char_type *data() { return data_; }
+ const char_type *data() const { return data_; }
+
+ size_t size() const { return size_; }
+ size_t capacity() const { return capacity_; }
+ void shrink_to_fit() {
+ if (size_ == capacity_)
+ return;
+ char_type *new_data = NULL;
+ if (size_ != 0) {
+ char_type *new_data = new char_type[size_];
+ assert(new_data != NULL);
+ memcpy(new_data, data_, size_ * sizeof(char_type));
+ }
+ delete[] data_;
+ capacity_ = size_;
+ data_ = new_data;
+ }
+ void reserve(size_t new_capacity) {
+ if (new_capacity <= capacity_)
+ return;
+ char_type *new_data = new char_type[new_capacity];
+ assert(new_data != NULL);
+ if (data_) {
+ memcpy(new_data, data_, size_ * sizeof(char_type));
+ delete[] data_;
+ }
+ capacity_ = new_capacity;
+ data_ = new_data;
+ }
+ void resize(size_t new_size) {
+ if (new_size <= capacity_) {
+ size_ = new_size;
+ return;
+ }
+ reserve(new_size);
+ size_ = new_size;
+ };
+
+ char_type &operator[](size_t pos) { return *(data() + pos); }
+
+ const char_type &operator[](size_t pos) const { return *(data() + pos); }
+};
+
+template <typename T>
+inline void swap(BasicBufferArray<T> &LHS,
+ BasicBufferArray<T> &RHS) UTILS_CXX11_NOEXCEPT {
+ LHS.swap(RHS);
+}
+
+extern template class BasicBufferArray<char>;
+extern template class BasicBufferArray<wchar_t>;
+typedef BasicBufferArray<char> BufferArray;
+typedef BasicBufferArray<wchar_t> WBufferArray;
+
+} // namespace utils
+#endif // SEAFILE_CLIENT_UTILS_STL_H_
--- /dev/null
+#include <stdlib.h>
+#include <stdio.h>
+#include <QHash>
+#include <QObject>
+#include <QApplication>
+#include <QRegExp>
+#include <QStringList>
+
+#include "utils/utils.h"
+#include "translate-commit-desc.h"
+#include "utils/file-utils.h"
+
+namespace {
+
+//const char *kTranslateContext = "MessageListener";
+
+QHash<QString, QString> *verbsMap = NULL;
+
+QHash<QString, QString>*
+getVerbsMap()
+{
+ if (!verbsMap) {
+ verbsMap = new QHash<QString, QString>;
+ verbsMap->insert("Added", QObject::tr("Added"));
+ verbsMap->insert("Added or modified", QObject::tr("Added or modified"));
+ verbsMap->insert("Deleted", QObject::tr("Deleted"));
+ verbsMap->insert("Removed", QObject::tr("Removed"));
+ verbsMap->insert("Modified", QObject::tr("Modified"));
+ verbsMap->insert("Renamed", QObject::tr("Renamed"));
+ verbsMap->insert("Moved", QObject::tr("Moved"));
+ verbsMap->insert("Added directory", QObject::tr("Added directory"));
+ verbsMap->insert("Removed directory", QObject::tr("Removed directory"));
+ verbsMap->insert("Renamed directory", QObject::tr("Renamed directory"));
+ verbsMap->insert("Moved directory", QObject::tr("Moved directory"));
+ }
+
+ return verbsMap;
+}
+
+QString translateLine(const QString line)
+{
+ QString operations = ((QStringList)getVerbsMap()->keys()).join("|");
+ QString pattern = QString("(%1) \"(.*)\"\\s?(and ([0-9]+) more (files|directories))?").arg(operations);
+
+ QRegExp regex(pattern);
+
+ if (regex.indexIn(line) < 0) {
+ return line;
+ }
+
+ QString op = regex.cap(1);
+ QString file_name = regex.cap(2);
+ QString has_more = regex.cap(3);
+ QString n_more = regex.cap(4);
+ QString more_type = regex.cap(5);
+
+ QString op_trans = getVerbsMap()->value(op, op);
+
+ QString type, ret;
+ if (has_more.length() > 0) {
+ if (more_type == "files") {
+ type = QObject::tr("files");
+ } else {
+ type = QObject::tr("directories");
+ }
+
+ QString more = QObject::tr("and %1 more").arg(n_more);
+ ret = QString("%1 \"%2\" %3 %4.").arg(op_trans).arg(file_name).arg(more).arg(type);
+ } else {
+ ret = QString("%1 \"%2\".").arg(op_trans).arg(file_name);
+ }
+
+ return ret;
+}
+
+} // namespace
+
+
+QString
+translateCommitDesc(const QString& input)
+{
+ QString value = input;
+ if (value.startsWith("Reverted repo")) {
+ value.replace("repo", "library");
+ }
+
+ if (value.startsWith("Reverted library")) {
+ return value.replace("Reverted library to status at", QObject::tr("Reverted library to status at"));
+ } else if (value.startsWith("Reverted file")) {
+ QRegExp regex("Reverted file \"(.*)\" to status at (.*)");
+
+ if (regex.indexIn(value) >= 0) {
+ QString name = regex.cap(1);
+ QString time = regex.cap(2);
+ return QObject::tr("Reverted file \"%1\" to status at %2.").arg(name).arg(time);
+ }
+
+ } else if (value.startsWith("Recovered deleted directory")) {
+ return value.replace("Recovered deleted directory", QObject::tr("Recovered deleted directory"));
+ } else if (value.startsWith("Changed library")) {
+ return value.replace("Changed library name or description", QObject::tr("Changed library name or description"));
+ } else if (value.startsWith("Merged") || value.startsWith("Auto merge")) {
+ return QObject::tr("Auto merge by %1 system").arg(getBrand());
+ }
+
+ QStringList lines = value.split("\n");
+ QStringList out;
+
+ for (int i = 0; i < lines.size(); i++) {
+ out << translateLine(lines.at(i));
+ }
+
+ return out.join("\n");
+}
+
+// path: the path of activity file or folder
+// file_name: the name of activity file item
+// repo_name: the name of activity repository item
+// obj_type: the object of activity item include (file, path, repository)
+// op_type: the operation type of obj_name
+// old_repo_name: when rename repo the origin repo name
+// old_path: when rename path the origin path name
+// old_name: when rename file the origin file name
+// clean_trash_days: the days since clean the trash
+// out_obj_desc: the description of obj_name
+// out out_op_desc: the description of opt_type
+void
+translateCommitDescV2(const QString& path, const QString& file_name, const QString& repo_name,
+ const QString& obj_type, const QString& op_type, const QString& old_repo_name,
+ const QString& old_path, const QString& old_name, int clean_trash_days,
+ QString *out_obj_desc, QString *out_op_desc)
+{
+ if (obj_type == "repo") {
+ if (op_type == "create") {
+ *out_op_desc = QObject::tr("Created library");
+ } else if (op_type == "rename") {
+ *out_op_desc = QObject::tr("Renamed library");
+ } else if (op_type == "delete") {
+ *out_op_desc = QObject::tr("Deleted library");
+ *out_obj_desc = repo_name;
+ } else if (op_type == "recover") {
+ *out_op_desc = QObject::tr("Restored library");
+ } else if (op_type == "clean_up_trash") {
+ if (clean_trash_days == 0) {
+ *out_op_desc = QObject::tr("Removed all items from trash");
+ } else {
+ *out_op_desc = QObject::tr("Removed items older than days %1 from trash").arg(clean_trash_days);
+ }
+ }
+
+ if (op_type == "rename") {
+ *out_obj_desc = old_repo_name + " => " + repo_name;
+ } else {
+ *out_obj_desc = repo_name;
+ }
+
+ } else if (obj_type == "draft") {
+ *out_op_desc = QObject::tr("Published draft");
+ *out_obj_desc = file_name;
+ } else if (obj_type == "file") {
+ if (op_type == "create") {
+ if (file_name.endsWith("(draft).md")) {
+ *out_op_desc = QObject::tr("Created draft");
+ } else {
+ *out_op_desc = QObject::tr("Created file");
+ }
+ } else if (op_type == "rename") {
+ *out_op_desc = QObject::tr("Renamed file");
+ } else if (op_type == "delete") {
+ if (file_name.endsWith("(draft).md")) {
+ *out_op_desc = QObject::tr("Deleted draft");
+ } else {
+ *out_op_desc = QObject::tr("Deleted file");
+ }
+ } else if (op_type == "recover") {
+ *out_op_desc = QObject::tr("Restored file");
+ } else if (op_type == "move") {
+ *out_op_desc = QObject::tr("Moved file");
+ } else if (op_type == "edit") {
+ *out_op_desc = QObject::tr("Updated file");
+ }
+
+ if (op_type == "rename") {
+ *out_obj_desc = old_name + " => " + file_name;
+ } else {
+ *out_obj_desc = file_name;
+ }
+
+ } else { //dir
+ if (op_type == "create") {
+ *out_op_desc = QObject::tr("Created folder");
+ } else if (op_type == "rename") {
+ *out_op_desc = QObject::tr("Renamed folder");
+ } else if (op_type == "delete") {
+ *out_op_desc = QObject::tr("Deleted folder");
+ } else if (op_type == "recover") {
+ *out_op_desc = QObject::tr("Restored folder");
+ } else if (op_type == "move") {
+ *out_op_desc = QObject::tr("Moved folder");
+ }
+ if (op_type == "rename") {
+ *out_obj_desc = old_path + " => " + path;
+ } else {
+ *out_obj_desc = path;
+ }
+ }
+
+}
--- /dev/null
+
+#ifndef SEAFILE_CELINT_TRANSLATE_COMMIT_DESC_H
+#define SEAFILE_CELINT_TRANSLATE_COMMIT_DESC_H
+
+#include <QString>
+
+QString
+translateCommitDesc (const QString& input);
+
+void
+translateCommitDescV2(const QString& path, const QString& file_name, const QString& repo_name,
+ const QString& obj_type, const QString& op_type, const QString& old_repo_name,
+ const QString& old_path, const QString& old_name, int clean_trash_days,
+ QString *out_obj_desc, QString *out_op_desc);
+
+#endif // SEAFILE_CELINT_TRANSLATE_COMMIT_DESC_H
--- /dev/null
+extern "C" {
+#include <searpc-client.h>
+
+#include <searpc.h>
+#include <seafile/seafile.h>
+#include <seafile/seafile-object.h>
+
+}
+
+#include <QtGlobal>
+
+#if defined(Q_OS_WIN32)
+#include <windows.h>
+#include <shellapi.h>
+#else
+#include <memory>
+#include <fts.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+#include <glib.h>
+
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QMessageBox>
+#include <QIcon>
+#include <QMainWindow>
+
+#include "utils/utils.h"
+#include "settings-mgr.h"
+#include "ui/uninstall-helper-dialog.h"
+#include "rpc/rpc-server.h"
+
+#if defined(Q_OS_WIN32)
+#include "utils/registry.h"
+#endif
+
+#include "uninstall-helpers.h"
+
+namespace {
+
+#if defined(Q_OS_WIN32)
+const char *kPreconfigureKeepConfigWhenUninstall = "PreconfigureKeepConfigWhenUninstall";
+#endif
+
+#if !defined(Q_OS_WIN32)
+int posix_rmdir(const QString &root)
+{
+ if (!QFileInfo(root).exists()) {
+ qWarning("dir %s doesn't exists", toCStr(root));
+ return -1;
+ }
+
+ std::unique_ptr<char[]> root_ptr(strdup(toCStr(root)));
+
+ char *paths[] = {root_ptr.get(), NULL};
+
+ // Using `FTS_PHYSICAL` here because we need `FTSENT` for the
+ // symbolic link in the directory and not the target it links to.
+ FTS *tree = fts_open(paths, (FTS_NOCHDIR | FTS_PHYSICAL), NULL);
+ if (tree == NULL) {
+ qWarning("failed to fts_open: %s", strerror(errno));
+ return -1;
+ }
+
+ FTSENT *node;
+ while ((node = fts_read(tree)) != NULL) {
+ // printf ("%s: fts_info = %d\n", node->fts_path, (int)(node->fts_info));
+ switch (node->fts_info) {
+ case FTS_DP:
+ // qWarning("removing directory %s", node->fts_path);
+ if (rmdir(node->fts_path) < 0 && errno != ENOENT) {
+ qWarning("failed to remove dir %s", node->fts_path);
+ }
+ break;
+ // `FTS_DEFAULT` would include any file type which is not
+ // explicitly described by any of the other `fts_info` values.
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ // `FTS_SLNONE` should never be the case as we don't set
+ // `FTS_COMFOLLOW` or `FTS_LOGICAL`. Adding here for completion.
+ case FTS_SLNONE:
+ // qWarning("removing file %s", node->fts_path);
+ if (unlink(node->fts_path) < 0 && errno != ENOENT) {
+ qWarning("failed to remove file %s", node->fts_path);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (errno != 0) {
+ fts_close(tree);
+ return -1;
+ }
+
+ if (fts_close(tree) < 0) {
+ return -1;
+ }
+ return 0;
+}
+#endif
+
+} // namespace
+
+int delete_dir_recursively(const QString& path_in)
+{
+ qWarning ("removing folder %s\n", toCStr(path_in));
+#if defined(Q_OS_WIN32)
+ const QString path = QDir::toNativeSeparators(QDir::cleanPath(path_in));
+ if (path.length() <= 3) {
+ // avoid errornous delete drives like C:/ D:/ E:/
+ return -1;
+ }
+
+ int len = path.length();
+
+ wchar_t *wpath = new wchar_t[len + 2];
+
+ wcscpy(wpath, path.toStdWString().c_str());
+ wpath[len + 1] = L'\0';
+
+ SHFILEOPSTRUCTW fileop;
+ fileop.hwnd = NULL; // no status display
+ fileop.wFunc = FO_DELETE; // delete operation
+ fileop.pFrom = wpath; // source file name as double null terminated string
+ fileop.pTo = NULL; // no destination needed
+ fileop.fFlags = FOF_NOCONFIRMATION|FOF_SILENT; // do not prompt the user
+
+ fileop.fAnyOperationsAborted = FALSE;
+ fileop.lpszProgressTitle = NULL;
+ fileop.hNameMappings = NULL;
+
+ int ret = SHFileOperationW(&fileop);
+
+ delete []wpath;
+
+ if (ret == 0) {
+ return 0;
+ } else {
+ return -1;
+ }
+ return 0;
+#else
+ return posix_rmdir(path_in);
+#endif
+}
+
+
+int get_ccnet_dir(QString *ret)
+{
+ QString path = defaultCcnetDir();
+
+ if (!QFileInfo(path).exists()) {
+ return -1;
+ }
+
+ *ret = path;
+ return 0;
+}
+
+int get_seafile_data_dir(const QString& ccnet_dir, QString *ret)
+{
+ QFile seafile_ini(QDir(ccnet_dir).filePath("seafile.ini"));
+ if (!seafile_ini.exists()) {
+ return -1;
+ }
+
+ if (!seafile_ini.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ return -1;
+ }
+
+ QTextStream input(&seafile_ini);
+ input.setCodec("UTF-8");
+
+ if (input.atEnd()) {
+ return -1;
+ }
+
+ QString path = input.readLine();
+ if (!QFileInfo(QDir(path).filePath("repo.db")).exists()) {
+ return -1;
+ }
+
+ *ret = path;
+ return 0;
+}
+
+void do_ping()
+{
+ SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+ if (!client->connect()) {
+ printf ("failed to connect to applet rpc server\n");
+ return;
+ }
+ QString resp;
+ if (client->sendPingCommand(&resp)) {
+ printf ("response: %s\n", toCStr(resp));
+ } else {
+ printf ("failed to send ping command\n");
+ }
+}
+
+void do_stop()
+{
+ SeafileAppletRpcServer::Client *client = SeafileAppletRpcServer::getClient();
+ if (!client->connect()) {
+ printf ("failed to connect to applet rpc server\n");
+ return;
+ }
+ if (client->sendExitCommand()) {
+ printf ("exit command: success\n");
+ } else {
+ printf ("exit command: failed\n");
+ }
+}
+
+#if defined(Q_OS_WIN32)
+int hasPreconfigureKeepConfigWhenUninstall()
+{
+ return RegElement::getPreconfigureIntValue(kPreconfigureKeepConfigWhenUninstall);
+}
+#endif
+
+void do_remove_user_data()
+{
+ do_stop();
+ set_seafile_auto_start(false);
+
+#if defined(Q_OS_WIN32)
+ if (hasPreconfigureKeepConfigWhenUninstall()) {
+ return;
+ }
+#endif
+
+ SettingsManager::removeAllSettings();
+
+ UninstallHelperDialog *dialog = new UninstallHelperDialog;
+
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
+
+ qApp->exec();
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_UNINSTALL_HELPERS_H
+#define SEAFILE_CLIENT_UTILS_UNINSTALL_HELPERS_H
+
+#include <QString>
+
+void do_ping();
+/**
+ * Stop running seafile client.
+ */
+void do_stop();
+
+/**
+ * Remove ccnet and seafile-data
+ */
+void do_remove_user_data();
+
+int get_ccnet_dir(QString *ret);
+int get_seafile_data_dir(const QString& ccnet_dir, QString *ret);
+int delete_dir_recursively(const QString& path_in);
+
+#endif // SEAFILE_CLIENT_UTILS_UNINSTALL_HELPERS_H
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_MAC_H_
+#define SEAFILE_CLIENT_UTILS_MAC_H_
+#include <QtGlobal>
+#ifdef Q_OS_MAC
+#include <QString>
+#include <vector>
+#include <QByteArray>
+
+typedef void DarkModeChangedCallback(bool value);
+
+namespace utils {
+namespace mac {
+// a list for os x versions https://support.apple.com/en-us/HT201260
+// release major minor patch
+// Yosemite 10 10 ?
+// Mavericks 10 9 ?
+// Mountain Lion 10 8 ?
+// Lion 10 7 ?
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch);
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch);
+bool isOSXYosemiteOrGreater();
+bool isOSXMavericksOrGreater();
+bool isOSXMountainLionOrGreater();
+bool isOSXLionOrGreater();
+
+void setDockIconStyle(bool hidden);
+void orderFrontRegardless(unsigned long long win_id, bool force = false);
+bool get_auto_start();
+void set_auto_start(bool enabled);
+void copyTextToPasteboard(const QString &text);
+
+bool is_darkmode();
+void set_darkmode_watcher(DarkModeChangedCallback *cb);
+
+QString fix_file_id_url(const QString &path);
+
+QString mainBundlePath();
+
+// load the missing part of ca certificates
+std::vector<QByteArray> getSystemCaCertificates();
+
+} // namespace mac
+} // namespace utils
+#else
+namespace utils {
+namespace mac {
+inline bool isOSXYosemiteOrGreater() { return false; }
+inline bool isOSXMavericksOrGreater() { return false; }
+inline bool isOSXMountainLionOrGreater() { return false; }
+inline bool isOSXLionOrGreater() { return false; }
+} // namespace mac
+} // namespace utils
+#endif /* Q_OS_MAC */
+
+#endif /* SEAFILE_CLIENT_UTILS_MAC_H_ */
--- /dev/null
+#include "utils-mac.h"
+
+#include <AvailabilityMacros.h>
+#import <Cocoa/Cocoa.h>
+#import <Security/Security.h>
+
+#include <openssl/asn1.h>
+#include <openssl/conf.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+#if !__has_feature(objc_arc)
+#error this file must be built with ARC support
+#endif
+
+// borrowed from AvailabilityMacros.h
+#ifndef MAC_OS_X_VERSION_10_10
+#define MAC_OS_X_VERSION_10_10 101000
+#endif
+#ifndef MAC_OS_X_VERSION_10_9
+#define MAC_OS_X_VERSION_10_9 1090
+#endif
+#ifndef MAC_OS_X_VERSION_10_8
+#define MAC_OS_X_VERSION_10_8 1080
+#endif
+#ifndef MAC_OS_X_VERSION_10_7
+#define MAC_OS_X_VERSION_10_7 1070
+#endif
+
+// ****************************************************************************
+// utils::mac::getSystemVersion
+// utils::mac::isAtLeastSystemVersion
+// ****************************************************************************
+
+namespace utils {
+namespace mac {
+namespace {
+unsigned osver_major = 0;
+unsigned osver_minor = 0;
+unsigned osver_patch = 0;
+inline bool isInitializedSystemVersion() { return osver_major != 0; }
+inline void initializeSystemVersion() {
+ if (isInitializedSystemVersion())
+ return;
+#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
+ NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
+ osver_major = version.majorVersion;
+ osver_minor = version.minorVersion;
+ osver_patch = version.patchVersion;
+#else
+ NSString *versionString = [[NSProcessInfo processInfo] operatingSystemVersionString];
+ NSArray *array = [versionString componentsSeparatedByString:@" "];
+ if (array.count < 2) {
+ osver_major = 10;
+ osver_minor = 7;
+ osver_patch = 0;
+ return;
+ }
+
+ NSArray *versionArray = [[array objectAtIndex:1] componentsSeparatedByString:@"."];
+ if (versionArray.count < 2) {
+ osver_major = 10;
+ osver_minor = 7;
+ osver_patch = 0;
+ return;
+ }
+ osver_major = [[versionArray objectAtIndex:0] intValue];
+ osver_minor = [[versionArray objectAtIndex:1] intValue];
+ if (versionArray.count > 2) {
+ osver_patch = [[versionArray objectAtIndex:2] intValue];
+ }
+#endif
+}
+
+inline bool _isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+ initializeSystemVersion();
+#define OSVER_TO_NUM(major, minor, patch) ((major << 20) + (minor << 10) + (patch))
+#define OSVER_SYS() OSVER_TO_NUM(osver_major, osver_minor, osver_patch)
+ if (OSVER_SYS() < OSVER_TO_NUM(major, minor, patch)) {
+ return false;
+ }
+#undef OSVER_SYS
+#undef OSVER_TO_NUM
+ return true;
+}
+// compile statically
+template<unsigned major, unsigned minor, unsigned patch>
+inline bool isAtLeastSystemVersion()
+{
+ return _isAtLeastSystemVersion(major, minor, patch);
+}
+} // anonymous namespace
+
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch) {
+ initializeSystemVersion();
+ *major = osver_major;
+ *minor = osver_minor;
+ *patch = osver_patch;
+}
+
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+ return _isAtLeastSystemVersion(major, minor, patch);
+}
+
+bool isOSXYosemiteOrGreater()
+{
+ return isAtLeastSystemVersion<10, 10, 0>();
+}
+
+bool isOSXMavericksOrGreater()
+{
+ return isAtLeastSystemVersion<10, 9, 0>();
+}
+
+bool isOSXMountainLionOrGreater()
+{
+ return isAtLeastSystemVersion<10, 8, 0>();
+}
+
+bool isOSXLionOrGreater()
+{
+ return isAtLeastSystemVersion<10, 7, 0>();
+}
+
+} // namespace mac
+} // namesapce utils
+
+// ****************************************************************************
+// darkmode related
+// ****************************************************************************
+@interface DarkmodeHelper : NSObject
+- (void)getDarkMode;
+@end
+
+static bool darkMode = false;
+static DarkModeChangedCallback *darkModeWatcher = NULL;
+@implementation DarkmodeHelper
+- (id) init {
+ self = [super init];
+
+ // darkmode is available version >= 10.10
+ if (utils::mac::isOSXYosemiteOrGreater()) {
+ [self getDarkMode];
+
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(darkModeChanged:)
+ name:@"AppleInterfaceThemeChangedNotification" object:nil];
+ }
+ return self;
+}
+
+- (void)darkModeChanged:(NSNotification *)aNotification
+{
+ bool oldDarkMode = darkMode;
+ [self getDarkMode];
+
+ if (oldDarkMode != darkMode && darkModeWatcher) {
+ darkModeWatcher(darkMode);
+ }
+}
+
+- (void)getDarkMode {
+ NSDictionary *dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
+ id style = [dict objectForKey:@"AppleInterfaceStyle"];
+ darkMode = ( style && [style isKindOfClass:[NSString class]] && NSOrderedSame == [style caseInsensitiveCompare:@"dark"]);
+}
+@end
+
+// ****************************************************************************
+// others
+// ****************************************************************************
+namespace utils {
+namespace mac {
+
+// another solution: hide dock icon when mainwindows is closed and show when
+// mainwindows is shown
+// http://stackoverflow.com/questions/16994331/multiprocessing-qt-app-how-can-i-limit-it-to-a-single-icon-in-the-macos-x-dock
+void setDockIconStyle(bool hidden) {
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+ OSStatus err;
+ if (hidden) {
+ // kProcessTransformToBackgroundApplication is not support on OSX 10.7 and before
+ // kProcessTransformToUIElementApplication is used for better fit when possible
+ unsigned major;
+ unsigned minor;
+ unsigned patch;
+ getSystemVersion(&major, &minor, &patch);
+ if (major == 10 && minor == 7)
+ err = TransformProcessType(&psn, kProcessTransformToBackgroundApplication);
+ else
+ err = TransformProcessType(&psn, kProcessTransformToUIElementApplication);
+ } else {
+ // kProcessTransformToForegroundApplication is supported on OSX 10.6 or later
+ err = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+ }
+ if (err != noErr)
+ qWarning("setDockIconStyle %s failure, status code: %d\n", (hidden ? "hidden" : "show"), err);
+}
+
+void orderFrontRegardless(unsigned long long win_id, bool force) {
+ NSView __weak *widget = (__bridge NSView*)(void*)win_id;
+ NSWindow *window = [widget window];
+ if(force || [window isVisible])
+ [window performSelector:@selector(orderFrontRegardless) withObject:nil afterDelay:0.05];
+}
+
+// https://bugreports.qt-project.org/browse/QTBUG-40449 is fixed in QT 5.4.1
+// TODO remove this and related code once qt 5.4.1 is widely used
+QString fix_file_id_url(const QString &path) {
+ if (!path.startsWith("/.file/id="))
+ return path;
+ const QString url = "file://" + path;
+ NSString *fileIdURL = [NSString stringWithCString:url.toUtf8().data()
+ encoding:NSUTF8StringEncoding];
+ NSURL *goodURL = [[NSURL URLWithString:fileIdURL] filePathURL];
+ NSString *filePath = goodURL.path; // readonly
+
+ QString retval = QString::fromUtf8([filePath UTF8String],
+ [filePath lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
+ return retval;
+}
+
+// original idea come from growl framework
+// http://growl.info/about
+bool get_auto_start()
+{
+ NSURL *itemURL = [[NSBundle mainBundle] bundleURL];
+ CFURLRef URLToToggle = (__bridge CFURLRef)itemURL;
+
+ bool found = false;
+
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
+ if (loginItems) {
+ UInt32 seed = 0U;
+ CFArrayRef currentLoginItems = LSSharedFileListCopySnapshot(loginItems,
+ &seed);
+ const CFIndex count = CFArrayGetCount(currentLoginItems);
+ for (CFIndex idx = 0; idx < count; ++idx) {
+ LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(currentLoginItems, idx);
+ CFURLRef outURL = NULL;
+
+ const UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
+#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
+ outURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, /*outError*/ NULL);
+ if (outURL == NULL) {
+#else
+ OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &outURL, /*outRef*/ NULL);
+ if (err != noErr || outURL == NULL) {
+#endif
+ if (outURL)
+ CFRelease(outURL);
+ continue;
+ }
+ found = CFEqual(outURL, URLToToggle);
+ CFRelease(outURL);
+
+ if (found)
+ break;
+ }
+ CFRelease(currentLoginItems);
+ CFRelease(loginItems);
+ }
+ return found;
+}
+
+void set_auto_start(bool enabled)
+{
+ NSURL *itemURL = [[NSBundle mainBundle] bundleURL];
+ CFURLRef URLToToggle = (__bridge CFURLRef)itemURL;
+
+ LSSharedFileListRef loginItems = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, /*options*/ NULL);
+ if (loginItems) {
+ UInt32 seed = 0U;
+ Boolean found;
+ LSSharedFileListItemRef existingItem = NULL;
+
+ CFArrayRef currentLoginItems = LSSharedFileListCopySnapshot(loginItems,
+ &seed);
+ const CFIndex count = CFArrayGetCount(currentLoginItems);
+ for (CFIndex idx = 0; idx < count; ++idx) {
+ LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(currentLoginItems, idx);
+ CFURLRef outURL = NULL;
+
+ const UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
+#if (__MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
+ outURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, /*outError*/ NULL);
+ if (outURL == NULL) {
+#else
+ OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &outURL, /*outRef*/ NULL);
+ if (err != noErr || outURL == NULL) {
+#endif
+ if (outURL)
+ CFRelease(outURL);
+ continue;
+ }
+ found = CFEqual(outURL, URLToToggle);
+ CFRelease(outURL);
+
+ if (found) {
+ existingItem = item;
+ break;
+ }
+ }
+
+ if (enabled && !found) {
+ NSString *displayName = @"Seafile Client";
+ IconRef icon = NULL;
+ FSRef ref;
+ // TODO: replace the deprecated CFURLGetFSRef
+ Boolean gotRef = CFURLGetFSRef(URLToToggle, &ref);
+ if (gotRef) {
+ OSStatus err = GetIconRefFromFileInfo(
+ &ref,
+ /*fileNameLength*/ 0,
+ /*fileName*/ NULL, kFSCatInfoNone,
+ /*catalogInfo*/ NULL, kIconServicesNormalUsageFlag, &icon,
+ /*outLabel*/ NULL);
+ if (err != noErr) {
+ if (icon)
+ CFRelease(icon);
+ icon = NULL;
+ }
+ }
+
+ LSSharedFileListItemRef newItem = LSSharedFileListInsertItemURL(
+ loginItems, kLSSharedFileListItemBeforeFirst,
+ (__bridge CFStringRef)displayName, icon, URLToToggle,
+ /*propertiesToSet*/ NULL, /*propertiesToClear*/ NULL);
+ if (newItem)
+ CFRelease(newItem);
+ if (icon)
+ CFRelease(icon);
+ } else if (!enabled && found) {
+ LSSharedFileListItemRemove(loginItems, existingItem);
+ }
+
+ CFRelease(currentLoginItems);
+ CFRelease(loginItems);
+ }
+}
+
+bool is_darkmode() {
+ static DarkmodeHelper *helper = nil;
+ if (!helper) {
+ helper = [[DarkmodeHelper alloc] init];
+ }
+ return darkMode;
+}
+void set_darkmode_watcher(DarkModeChangedCallback *cb) {
+ darkModeWatcher = cb;
+}
+
+void copyTextToPasteboard(const QString &text) {
+ NSString *text_data = [NSString stringWithUTF8String:text.toUtf8().data()];
+ NSPasteboard *paste_board = [NSPasteboard generalPasteboard];
+ [paste_board clearContents];
+ [paste_board declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
+ [paste_board writeObjects:@[text_data]];
+}
+
+QString mainBundlePath() {
+ NSURL *url = [[NSBundle mainBundle] bundleURL];
+ return [[url path] UTF8String];
+}
+
+static inline bool isSslPolicy(SecPolicyRef policy) {
+ bool is_ssl = false;
+ CFDictionaryRef properties = NULL;
+ if (!policy)
+ return false;
+ if ((properties = SecPolicyCopyProperties(policy)) == NULL)
+ return false;
+ CFTypeRef value = NULL;
+ if (CFDictionaryGetValueIfPresent(properties, kSecPolicyOid,
+ (const void **)&value) &&
+ CFEqual(value, kSecPolicyAppleSSL))
+ is_ssl = true;
+
+ ;
+ CFRelease(properties);
+ return is_ssl;
+}
+
+static bool isCertificateDistrustedByUser(SecCertificateRef cert,
+ SecTrustSettingsDomain domain) {
+ CFArrayRef trustSettings;
+ // On return, an array of CFDictionary objects specifying the trust settings
+ // for the certificate
+ OSStatus status = SecTrustSettingsCopyTrustSettings(cert, domain, &trustSettings);
+ if (status != errSecSuccess)
+ return false;
+
+ bool distrusted = false;
+
+ CFNumberRef result;
+ SecTrustSettingsResult result_val;
+ CFIndex size = CFArrayGetCount(trustSettings);
+ for (CFIndex i = 0; i < size; ++i) {
+ CFDictionaryRef trustSetting = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, i);
+ SecPolicyRef policy = (SecPolicyRef)CFDictionaryGetValue(trustSetting, kSecTrustSettingsPolicy);
+
+ if (isSslPolicy(policy) &&
+ CFDictionaryGetValueIfPresent(trustSetting, kSecTrustSettingsResult,
+ (const void **)&result)) {
+ if (!CFNumberGetValue(result, kCFNumberIntType, &result_val))
+ continue;
+ switch (result_val) {
+ case kSecTrustSettingsResultTrustRoot:
+ case kSecTrustSettingsResultTrustAsRoot:
+ case kSecTrustSettingsResultUnspecified:
+ distrusted = false;
+ break;
+ case kSecTrustSettingsResultInvalid:
+ case kSecTrustSettingsResultDeny:
+ default:
+ distrusted = true;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ CFRelease(trustSettings);
+
+ return distrusted;
+}
+
+bool isCertExpired(const unsigned char **bytes, size_t len) {
+ using X509_ptr = std::unique_ptr<X509, decltype(&X509_free)>;
+ X509_ptr cert(d2i_X509(NULL, bytes, len), X509_free);
+ return X509_cmp_current_time (X509_get_notAfter(cert.get())) < 0;
+}
+
+static void
+appendCaCertificateFromSecurityStore(std::vector<QByteArray> *retval,
+ SecTrustSettingsDomain domain) {
+ CFArrayRef certs;
+ OSStatus status = 1;
+ status = SecTrustSettingsCopyCertificates(domain, &certs);
+ if (status != errSecSuccess)
+ return;
+
+ CFIndex size = CFArrayGetCount(certs);
+ for (CFIndex i = 0; i < size; ++i) {
+ SecCertificateRef cert =
+ (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
+
+ if (isCertificateDistrustedByUser(cert, kSecTrustSettingsDomainSystem) ||
+ isCertificateDistrustedByUser(cert, kSecTrustSettingsDomainAdmin) ||
+ isCertificateDistrustedByUser(cert, kSecTrustSettingsDomainUser)) {
+ CFStringRef name;
+ status = SecCertificateCopyCommonName(cert, &name);
+ if (status == errSecSuccess && name != nil) {
+ qWarning("declining a distrusted CA certificate from the system"
+ "store with common name %s",
+ [(__bridge NSString*)name UTF8String]);
+ CFRelease(name);
+ }
+ else
+ qWarning("declining a distrusted CA certificate from the system store");
+ continue;
+ }
+
+ // copy if trusted
+ CFDataRef data;
+ data = SecCertificateCopyData(cert);
+
+ if (data == NULL) {
+ qWarning("error retrieving a CA certificate from the system store");
+ } else {
+ QByteArray raw_data((const char *)CFDataGetBytePtr(data), CFDataGetLength(data));
+ const unsigned char *pdata = (const unsigned char *)CFDataGetBytePtr(data);
+ // If one of the certs is expired, curl would abort
+ // loading all the certs
+ if (!isCertExpired(&pdata, raw_data.size())) {
+ retval->push_back(raw_data);
+ }
+ CFRelease(data);
+ }
+ }
+ CFRelease(certs);
+}
+
+std::vector<QByteArray> getSystemCaCertificates() {
+ std::vector<QByteArray> retval;
+ appendCaCertificateFromSecurityStore(&retval, kSecTrustSettingsDomainSystem);
+ appendCaCertificateFromSecurityStore(&retval, kSecTrustSettingsDomainAdmin);
+ appendCaCertificateFromSecurityStore(&retval, kSecTrustSettingsDomainUser);
+ return retval;
+}
+
+} // namespace mac
+} // namespace utils
--- /dev/null
+#include <windows.h>
+#include <shellapi.h>
+#include <wincrypt.h>
+#include <glib.h>
+
+#include <QLibrary>
+#include <QPair>
+#include <QString>
+
+#include "utils/utils-win.h"
+
+namespace utils {
+namespace win {
+
+namespace {
+OSVERSIONINFOEX osver; // static variable, all zero
+bool osver_failure = false;
+
+// From http://stackoverflow.com/a/36909293/1467959 and http://yamatyuu.net/computer/program/vc2013/rtlgetversion/index.html
+typedef void(WINAPI *RtlGetVersion_FUNC)(OSVERSIONINFOEXW *);
+BOOL CustomGetVersion(OSVERSIONINFOEX *os)
+{
+ HMODULE hMod;
+ RtlGetVersion_FUNC func;
+#ifdef UNICODE
+ OSVERSIONINFOEXW *osw = os;
+#else
+ OSVERSIONINFOEXW o;
+ OSVERSIONINFOEXW *osw = &o;
+#endif
+
+ hMod = LoadLibrary(TEXT("ntdll.dll"));
+ if (hMod) {
+ func = (RtlGetVersion_FUNC)GetProcAddress(hMod, "RtlGetVersion");
+ if (func == 0) {
+ FreeLibrary(hMod);
+ return FALSE;
+ }
+ ZeroMemory(osw, sizeof(*osw));
+ osw->dwOSVersionInfoSize = sizeof(*osw);
+ func(osw);
+#ifndef UNICODE
+ os->dwBuildNumber = osw->dwBuildNumber;
+ os->dwMajorVersion = osw->dwMajorVersion;
+ os->dwMinorVersion = osw->dwMinorVersion;
+ os->dwPlatformId = osw->dwPlatformId;
+ os->dwOSVersionInfoSize = sizeof(*os);
+ DWORD sz = sizeof(os->szCSDVersion);
+ WCHAR *src = osw->szCSDVersion;
+ unsigned char *dtc = (unsigned char *)os->szCSDVersion;
+ while (*src)
+ *dtc++ = (unsigned char)*src++;
+ *dtc = '\0';
+#endif
+
+ } else
+ return FALSE;
+ FreeLibrary(hMod);
+ return TRUE;
+}
+
+
+inline bool isInitializedSystemVersion() { return osver.dwOSVersionInfoSize != 0; }
+inline void initializeSystemVersion() {
+ if (isInitializedSystemVersion()) {
+ return;
+ }
+ osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ // according to the document,
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724451%28v=vs.85%29.aspx
+ // this API will be unavailable once windows 10 is out
+ if (!CustomGetVersion(&osver)) {
+ qWarning("failed to get OS vesion.");
+ osver_failure = true;
+ }
+}
+
+inline bool _isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+ initializeSystemVersion();
+ if (osver_failure) {
+ return false;
+ }
+#define OSVER_TO_NUM(major, minor, patch) ((major << 20) + (minor << 10) + (patch))
+#define OSVER_SYS(ver) OSVER_TO_NUM(ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor)
+ if (OSVER_SYS(osver) < OSVER_TO_NUM(major, minor, patch)) {
+ return false;
+ }
+#undef OSVER_SYS
+#undef OSVER_TO_NUM
+ return true;
+}
+
+// compile statically
+template<unsigned major, unsigned minor, unsigned patch>
+inline bool isAtLeastSystemVersion()
+{
+ return _isAtLeastSystemVersion(major, minor, patch);
+}
+} // anonymous namesapce
+
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch)
+{
+ initializeSystemVersion();
+ // default to XP
+ if (osver_failure) {
+ *major = 5;
+ *minor = 1;
+ *patch = 0;
+ }
+ *major = osver.dwMajorVersion;
+ *minor = osver.dwMinorVersion;
+ *patch = osver.wServicePackMajor;
+}
+
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch)
+{
+ return _isAtLeastSystemVersion(major, minor, patch);
+}
+
+bool isWindowsVistaOrHigher()
+{
+ return isAtLeastSystemVersion<6, 0, 0>();
+}
+
+bool isWindows7OrHigher()
+{
+ return isAtLeastSystemVersion<6, 1, 0>();
+}
+
+bool isWindows8OrHigher()
+{
+ return isAtLeastSystemVersion<6, 2, 0>();
+}
+
+bool isWindows8Point1OrHigher()
+{
+ return isAtLeastSystemVersion<6, 3, 0>();
+}
+
+bool isWindows10OrHigher()
+{
+ return isAtLeastSystemVersion<10, 0, 0>();
+}
+
+typedef HRESULT (WINAPI *GetDpiForMonitor)(HMONITOR,int,UINT *,UINT *);
+typedef BOOL (WINAPI *SetProcessDPIAware)();
+GetDpiForMonitor getDpiForMonitor;
+SetProcessDPIAware setProcessDPIAware;
+typedef QPair<qreal, qreal> QDpi;
+
+static inline QDpi monitorDPI(HMONITOR hMonitor)
+{
+ UINT dpiX;
+ UINT dpiY;
+ if (SUCCEEDED(getDpiForMonitor(hMonitor, 0, &dpiX, &dpiY)))
+ return QDpi(dpiX, dpiY);
+ return QDpi(0, 0);
+}
+
+static inline QDpi deviceDPI(HDC hdc)
+{
+ return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
+}
+
+static bool monitorData(HMONITOR hMonitor, QDpi *dpi_out)
+{
+ MONITORINFOEX info;
+ memset(&info, 0, sizeof(MONITORINFOEX));
+ info.cbSize = sizeof(MONITORINFOEX);
+ if (GetMonitorInfo(hMonitor, &info) == FALSE)
+ return false;
+
+ if (QString::fromLocal8Bit(info.szDevice) == QLatin1String("WinDisc")) {
+ return false;
+ } else {
+ QDpi dpi = monitorDPI(hMonitor);
+ if (dpi.first) {
+ *dpi_out = dpi;
+ return true;
+ } else {
+ HDC hdc = CreateDC(info.szDevice, NULL, NULL, NULL);
+ if (hdc) {
+ *dpi_out = deviceDPI(hdc);
+ DeleteDC(hdc);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool monitorEnumCallback(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM p)
+{
+ QDpi *data = (QDpi *)p;
+ if (monitorData(hMonitor, data)) {
+ // printf ("dpi = %d %d\n", (int)data->first, (int)data->second);
+ return false;
+ }
+ return true;
+}
+
+static bool readDPI(QDpi *dpi)
+{
+ EnumDisplayMonitors(0, 0, (MONITORENUMPROC)monitorEnumCallback, (LPARAM)dpi);
+ return dpi->first != 0;
+}
+
+
+// QT's HDPI doesn't support non-integer scale factors, but QT_SCALE_FACTOR
+// environment variable could work with them. So here we calculate the scaling
+// factor (by reading the screen DPI), and update the value QT_SCALE_FACTOR with
+// it.
+//
+// NOTE: The code below only supports single monitor. For multiple monitors we
+// need to detect the dpi of each monitor and set QT_AUTO_SCREEN_SCALE_FACTOR
+// accordingly. We may do that in the future.
+bool fixQtHDPINonIntegerScaling()
+{
+ // Only do this on win8/win10
+ if (!isWindows8OrHigher()) {
+ return false;
+ }
+ // Don't overwrite the user sepcified scaling factors
+ if (!qgetenv("QT_SCALE_FACTOR").isEmpty() || !qgetenv("QT_SCREEN_SCALE_FACTORS").isEmpty()) {
+ return true;
+ }
+ // Don't overwrite the user sepcified multi-screen scaling factors
+ if (!qgetenv("QT_AUTO_SCREEN_SCALE_FACTOR").isEmpty()) {
+ return true;
+ }
+
+ // GetDpiForMonitor and SetProcessDPIAware are only available on win8/win10.
+ //
+ // See:
+ // - GetDpiForMonitor https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx
+ // - SetProcessDPIAware https://msdn.microsoft.com/en-us/library/windows/desktop/ms633543(v=vs.85).aspx
+ QLibrary shcore_dll(QString("SHCore"));
+ getDpiForMonitor = (GetDpiForMonitor)shcore_dll.resolve("GetDpiForMonitor");
+ if (getDpiForMonitor == nullptr) {
+ return false;
+ }
+
+ QLibrary user32_dll(QString("user32"));
+ setProcessDPIAware = (SetProcessDPIAware)user32_dll.resolve("SetProcessDPIAware");
+ if (setProcessDPIAware == nullptr) {
+ return false;
+ }
+
+ // Turn off system scaling, otherwise we'll always see a 96 DPI virtual screen.
+ if (!setProcessDPIAware()) {
+ return false;
+ }
+
+ QDpi dpi;
+ if (!readDPI(&dpi)) {
+ return false;
+ }
+
+ if (dpi.first <= 96) {
+ return false;
+ }
+
+ // See the "DPI and the Desktop Scaling Factor" https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx#dpi_and_the_desktop_scaling_factor
+ // Specifically, MSDN says:
+ // 96 DPI = 100% scaling
+ // 120 DPI = 125% scaling
+ // 144 DPI = 150% scaling
+ // 192 DPI = 200% scaling
+ double scaling_factor = ((double)(dpi.first)) / 96.0;
+ QString factor = QString::number(scaling_factor);
+
+ // Use QT_SCREEN_SCALE_FACTORS instead of QT_SCALE_FACTOR. The latter would
+ // scale the font, which has already been scaled by the system.
+ //
+ // See also http://lists.qt-project.org/pipermail/interest/2015-October/019242.html
+ g_setenv("QT_SCREEN_SCALE_FACTORS", factor.toUtf8().data(), 1);
+ // printf("set QT_SCALE_FACTOR to %s\n", factor.toUtf8().data());
+ return true;
+}
+
+char *b64encode(const char *input)
+{
+ char buf[32767] = {0};
+ DWORD retlen = 32767;
+ CryptBinaryToString((BYTE*) input, strlen(input), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, buf, &retlen);
+ return strdup(buf);
+}
+
+std::string getLocalPipeName(const char *pipe_name)
+{
+ DWORD buf_char_count = 32767;
+ char user_name_buf[buf_char_count];
+
+ if (GetUserName(user_name_buf, &buf_char_count) == 0) {
+ qWarning ("Failed to get user name, GLE=%lu\n",
+ GetLastError());
+ return pipe_name;
+ }
+ else {
+ std::string ret(pipe_name);
+ char *encoded = b64encode(user_name_buf);
+ ret += encoded;
+ free(encoded);
+ return ret;
+ }
+}
+
+// Qt's QProcess function cannot invoke programs that require administrator privileges,
+// so we need windows api funtion to invoke the program that require adminstrator privileges.
+DWORD runShellAsAdministrator(LPCSTR cmd, LPCSTR arg, int n_show)
+{
+ SHELLEXECUTEINFO shell_exec_info = {0};
+ shell_exec_info.cbSize = sizeof(SHELLEXECUTEINFO);
+ shell_exec_info.fMask = SEE_MASK_NOCLOSEPROCESS;
+ shell_exec_info.hwnd = NULL;
+ shell_exec_info.lpVerb = "runas";
+ shell_exec_info.lpFile = cmd;
+ shell_exec_info.lpParameters = arg;
+ shell_exec_info.lpDirectory = NULL;
+ shell_exec_info.nShow = n_show;
+ shell_exec_info.hInstApp = NULL;
+
+ BOOL ret = ShellExecuteEx(&shell_exec_info);
+ WaitForSingleObject(shell_exec_info.hProcess, INFINITE);
+
+ DWORD exit_code=0;
+ GetExitCodeProcess(shell_exec_info.hProcess, &exit_code);
+ CloseHandle(shell_exec_info.hProcess);
+ return exit_code;
+}
+
+
+} // namespace win
+
+} // namespace utils
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_WIN_H_
+#define SEAFILE_CLIENT_UTILS_WIN_H_
+#include <QtGlobal>
+
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#endif
+
+#ifdef Q_OS_WIN32
+namespace utils {
+namespace win {
+// a list for windows versions https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833%28v=vs.85%29.aspx
+// Windows Relaese major minor patch(SP)
+// windows 10: 10, 0, ?
+// windows 8.1: 6, 3, ?
+// windows 2012 R2: 6, 3, ?
+// windows 8: 6, 2, ?
+// windows 2012: 6, 2, ?
+// windows 7: 6, 1, ?
+// windows 2008 R2: 6, 1, ?
+// windows Vista: 6, 0, ?
+// windows 2008: 6, 0, ?
+// windows 2003 R2: 5, 2, ?
+// windows 2003: 5, 2, ?
+// windows XP x64: 5, 2, ?
+// windows XP: 5, 1, ?
+// windows 2000: 5, 0, ?
+void getSystemVersion(unsigned *major, unsigned *minor, unsigned *patch);
+bool isAtLeastSystemVersion(unsigned major, unsigned minor, unsigned patch);
+
+bool isWindowsVistaOrGreater();
+bool isWindows7OrGreater();
+bool isWindows8OrGreater();
+bool isWindows8Point1OrGreater();
+bool isWindows10OrHigher();
+bool fixQtHDPINonIntegerScaling();
+std::string getLocalPipeName(const char *pipeName);
+DWORD runShellAsAdministrator(LPCSTR cmd, LPCSTR arg, int n_show);
+} // namespace win
+} // namespace utils
+#endif
+
+
+#endif // SEAFILE_CLIENT_UTILS_WIN_H_
--- /dev/null
+#include <cassert>
+#include <errno.h>
+#include <dirent.h>
+#include <cstdio>
+#include <cstdlib>
+#include <unistd.h>
+#include <sqlite3.h>
+#include <glib.h>
+#include <cstring>
+#include <QObject>
+#include <QString>
+#include <QSettings>
+#include <QProcess>
+#include <QDesktopServices>
+#include <QHostInfo>
+#include <jansson.h>
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+#include <QUrlQuery>
+#endif
+
+#include "utils/utils-mac.h"
+#include "utils/utils-win.h"
+
+#if defined(Q_OS_MAC)
+ #include <sys/sysctl.h>
+#elif defined(Q_OS_WIN32)
+ #include <windows.h>
+ #include <psapi.h>
+#endif
+
+#include <QMap>
+#include <QVariant>
+#include <QDebug>
+#include <QDateTime>
+#include <QCryptographicHash>
+#include <QSslCipher>
+#include <QSslCertificate>
+
+#include "seafile-applet.h"
+#include "rpc/rpc-client.h"
+
+#include "utils/utils.h"
+
+namespace {
+
+const char *kSeafileClientBrand = "Seafile";
+#if defined(Q_OS_WIN32)
+const char *kCcnetConfDir = "ccnet";
+#else
+const char *kCcnetConfDir = ".ccnet";
+#endif
+
+#ifdef Q_OS_LINUX
+/// \brief call xdg-mime to find out the mime filetype X11 recognizes it as
+/// xdg-mime's usage:
+/// xdg-mime query filetype <filename>
+/// stdout: mime-type
+bool getMimeTypeFromXdgUtils(const QString &filepath, QString *mime)
+{
+ QProcess subprocess;
+ QStringList args("query");
+ args.push_back("filetype");
+ args.push_back(filepath);
+ subprocess.start(QLatin1String("xdg-mime"), args);
+ subprocess.waitForFinished(-1);
+ if (subprocess.exitCode())
+ return false;
+ *mime = subprocess.readAllStandardOutput();
+ *mime = mime->trimmed();
+ if (mime->isEmpty())
+ return false;
+ return true;
+}
+
+/// \brief call xdg-mime to find out the application X11 opens with by mime filetype
+/// xdg-mime's usage:
+/// xdg-mime query default <filename>
+/// stdout: application
+bool getOpenApplicationFromXdgUtils(const QString &mime, QString *application)
+{
+ QProcess subprocess;
+ QStringList args("query");
+ args.push_back("default");
+ args.push_back(mime);
+ subprocess.start(QLatin1String("xdg-mime"), args);
+ subprocess.waitForFinished(-1);
+ if (subprocess.exitCode())
+ return false;
+ *application = subprocess.readAllStandardOutput();
+ *application = application->trimmed();
+ if (application->isEmpty())
+ return false;
+ return true;
+}
+#endif
+
+} // namespace
+
+
+QString defaultCcnetDir() {
+ const char *env = g_getenv("CCNET_CONF_DIR");
+ if (env) {
+ return QString::fromUtf8(env);
+ } else {
+ return QDir::home().filePath(kCcnetConfDir);
+ }
+}
+
+QString defaultDownloadDir() {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ static QStringList list = QStandardPaths::standardLocations(QStandardPaths::DownloadLocation);
+ if (!list.empty())
+ return list.front();
+#endif
+ // qt4 don't have QStandardPaths, use glib's as fallback
+ return QString::fromUtf8(g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD));
+}
+
+bool openInNativeExtension(const QString &path) {
+#if defined(Q_OS_WIN32)
+ //call ShellExecute internally
+ return QDesktopServices::openUrl(QUrl::fromLocalFile(path));
+#elif defined(Q_OS_MAC)
+ // mac's open program, it will fork to open the file in a subprocess
+ // so we will wait for it to check whether it succeeds or not
+ QProcess subprocess;
+ subprocess.start(QLatin1String("open"), QStringList(path));
+ subprocess.waitForFinished(-1);
+ return subprocess.exitCode() == 0;
+#elif defined(Q_OS_LINUX)
+ // unlike mac's open program, xdg-open won't fork a new subprocess to open
+ // the file will block until the application returns, so we won't wait for it
+ // and we need another approach to check if it works
+
+ // find out if the file can be opened by xdg-open, xdg-mime
+ // usually they are installed in xdg-utils installed by default
+ QString mime_type;
+ if (!getMimeTypeFromXdgUtils(path, &mime_type))
+ return false;
+ // don't open this type of files from xdg-mime
+ if (mime_type == "application/octet-stream")
+ return false;
+ // in fact we need to filter out files like application/x-executable
+ // but it is not necessary since getMimeTypeFromXdg will return false for
+ // it!
+ QString application;
+ if (!getOpenApplicationFromXdgUtils(mime_type, &application))
+ return false;
+
+ return QProcess::startDetached(QLatin1String("xdg-open"),
+ QStringList(path));
+#else
+ return false;
+#endif
+}
+
+bool showInGraphicalShell(const QString& path) {
+#if defined(Q_OS_WIN32)
+ QStringList params;
+ if (!QFileInfo(path).isDir())
+ params << QLatin1String("/select,");
+ params << QDir::toNativeSeparators(path);
+ return QProcess::startDetached(QLatin1String("explorer.exe"), params);
+#elif defined(Q_OS_MAC)
+ QStringList scriptArgs;
+ scriptArgs << QLatin1String("-e")
+ << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"")
+ .arg(path);
+ QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs);
+ scriptArgs.clear();
+ scriptArgs << QLatin1String("-e")
+ << QLatin1String("tell application \"Finder\" to activate");
+ QProcess::execute("/usr/bin/osascript", scriptArgs);
+ return true;
+#else
+ return QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(path).absolutePath()));
+#endif
+}
+
+typedef bool (*SqliteRowFunc) (sqlite3_stmt *stmt, void *data);
+
+sqlite3_stmt *
+sqlite_query_prepare (sqlite3 *db, const char *sql)
+{
+ sqlite3_stmt *stmt;
+ int result;
+
+ result = sqlite3_prepare_v2 (db, sql, -1, &stmt, NULL);
+
+ if (result != SQLITE_OK) {
+ const gchar *str = sqlite3_errmsg (db);
+
+ g_warning ("Couldn't prepare query, error:%d->'%s'\n\t%s\n",
+ result, str ? str : "no error given", sql);
+
+ return NULL;
+ }
+
+ return stmt;
+}
+
+int sqlite_query_exec (sqlite3 *db, const char *sql)
+{
+ char *errmsg = NULL;
+ int result;
+
+ result = sqlite3_exec (db, sql, NULL, NULL, &errmsg);
+
+ if (result != SQLITE_OK) {
+ if (errmsg != NULL) {
+ g_warning ("SQL error: %d - %s\n:\t%s\n", result, errmsg, sql);
+ sqlite3_free (errmsg);
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+int sqlite_foreach_selected_row (sqlite3 *db, const char *sql,
+ SqliteRowFunc callback, void *data)
+{
+ sqlite3_stmt *stmt;
+ int result;
+ int n_rows = 0;
+
+ stmt = sqlite_query_prepare (db, sql);
+ if (!stmt) {
+ return -1;
+ }
+
+ while (1) {
+ result = sqlite3_step (stmt);
+ if (result != SQLITE_ROW)
+ break;
+ n_rows++;
+ if (!callback (stmt, data))
+ break;
+ }
+
+ if (result == SQLITE_ERROR) {
+ const gchar *s = sqlite3_errmsg (db);
+
+ g_warning ("Couldn't execute query, error: %d->'%s'\n",
+ result, s ? s : "no error given");
+ sqlite3_finalize (stmt);
+ return -1;
+ }
+
+ sqlite3_finalize (stmt);
+ return n_rows;
+}
+
+int checkdir_with_mkdir (const char *dir)
+{
+#if defined(Q_OS_WIN32)
+ int ret;
+ char *path = g_strdup(dir);
+ char *p = (char *)path + strlen(path) - 1;
+ while (*p == '\\' || *p == '/') *p-- = '\0';
+ ret = g_mkdir_with_parents(path, 0755);
+ g_free (path);
+ return ret;
+#else
+ return g_mkdir_with_parents(dir, 0755);
+#endif
+}
+
+
+#if defined(Q_OS_WIN32)
+static LONG
+get_win_run_key (HKEY *pKey)
+{
+ const char *key_run = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
+ LONG result = RegOpenKeyEx(
+ /* We don't use HKEY_LOCAL_MACHINE here because that requires
+ * seaf-daemon to run with admin privilege. */
+ HKEY_CURRENT_USER,
+ key_run,
+ 0L,KEY_WRITE | KEY_READ,
+ pKey);
+ if (result != ERROR_SUCCESS) {
+ qWarning("Failed to open Registry key %s\n", key_run);
+ }
+
+ return result;
+}
+
+static int
+add_to_auto_start (const wchar_t *appname_w, const wchar_t *path_w)
+{
+ HKEY hKey;
+ LONG result = get_win_run_key(&hKey);
+ if (result != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ DWORD n = sizeof(wchar_t) * (wcslen(path_w) + 1);
+
+ result = RegSetValueExW (hKey, appname_w,
+ 0, REG_SZ, (const BYTE *)path_w, n);
+
+ RegCloseKey(hKey);
+ if (result != ERROR_SUCCESS) {
+ qWarning("Failed to create auto start value\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+delete_from_auto_start(const wchar_t *appname)
+{
+ HKEY hKey;
+ LONG result = get_win_run_key(&hKey);
+ if (result != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ result = RegDeleteValueW (hKey, appname);
+ RegCloseKey(hKey);
+ if (result != ERROR_SUCCESS) {
+ qWarning("Failed to remove auto start value");
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+get_seafile_auto_start()
+{
+ HKEY hKey;
+ LONG result = get_win_run_key(&hKey);
+ if (result != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ char buf[MAX_PATH] = {0};
+ DWORD len = sizeof(buf);
+ result = RegQueryValueExW (hKey, /* Key */
+ getBrand().toStdWString().c_str(), /* value */
+ NULL, /* reserved */
+ NULL, /* output type */
+ (LPBYTE)buf, /* output data */
+ &len); /* output length */
+
+ RegCloseKey(hKey);
+ if (result != ERROR_SUCCESS) {
+ /* seafile applet auto start no set */
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+set_seafile_auto_start(bool on)
+{
+ int result = 0;
+ if (on) {
+ /* turn on auto start */
+ wchar_t applet_path[MAX_PATH];
+ if (GetModuleFileNameW (NULL, applet_path, MAX_PATH) == 0) {
+ return -1;
+ }
+
+ result = add_to_auto_start (getBrand().toStdWString().c_str(), applet_path);
+
+ } else {
+ /* turn off auto start */
+ result = delete_from_auto_start(getBrand().toStdWString().c_str());
+ }
+ return result;
+}
+
+#elif defined(Q_OS_MAC)
+int
+get_seafile_auto_start()
+{
+ return utils::mac::get_auto_start();
+}
+
+int
+set_seafile_auto_start(bool on)
+{
+ bool was_on = utils::mac::get_auto_start();
+ if (on != was_on)
+ utils::mac::set_auto_start(on);
+ return on;
+}
+#else
+int
+get_seafile_auto_start()
+{
+ return 0;
+}
+
+int
+set_seafile_auto_start(bool /* on */)
+{
+ return 0;
+}
+
+#endif
+
+int
+set_seafile_dock_icon_style(bool hidden)
+{
+#if defined(Q_OS_MAC)
+ utils::mac::setDockIconStyle(hidden);
+#endif
+ return 0;
+}
+
+bool parse_key_value_pairs (char *string, KeyValueFunc func, void *data)
+{
+ char *line = string, *next, *space;
+ char *key, *value;
+
+ while (*line) {
+ /* handle empty line */
+ if (*line == '\n') {
+ ++line;
+ continue;
+ }
+
+ for (next = line; *next != '\n' && *next; ++next) ;
+ *next = '\0';
+
+ for (space = line; space < next && *space != ' '; ++space) ;
+ if (*space != ' ') {
+ return false;
+ }
+ *space = '\0';
+ key = line;
+ value = space + 1;
+
+ if (func(data, key, value) == FALSE)
+ return false;
+
+ line = next + 1;
+ }
+ return true;
+}
+
+QString getBrand()
+{
+ return QString::fromUtf8(kSeafileClientBrand);
+}
+
+static
+QList<QVariant> listFromJSON(json_t *array)
+{
+ QList<QVariant> ret;
+ size_t array_size = json_array_size(array);
+ json_t *value;
+
+ for(size_t index = 0; index < array_size &&
+ (value = json_array_get(array, index)); ++index) {
+ /* block of code that uses index and value */
+ QVariant v;
+ if (json_is_object(value)) {
+ v = mapFromJSON(value, NULL);
+ } else if (json_is_array(value)) {
+ v = listFromJSON(value);
+ } else if (json_is_string(value)) {
+ v = QString::fromUtf8(json_string_value(value));
+ } else if (json_is_integer(value)) {
+ v = json_integer_value(value);
+ } else if (json_is_real(value)) {
+ v = json_real_value(value);
+ } else if (json_is_boolean(value)) {
+ v = json_is_true(value);
+ }
+ if (v.isValid()) {
+ ret.push_back(v);
+ }
+ }
+ return ret;
+}
+
+QMap<QString, QVariant> mapFromJSON(json_t *json, json_error_t *error)
+{
+ QMap<QString, QVariant> dict;
+ void *member;
+ const char *key;
+ json_t *value;
+
+ for (member = json_object_iter(json); member; member = json_object_iter_next(json, member)) {
+ key = json_object_iter_key(member);
+ value = json_object_iter_value(member);
+
+ QString k = QString::fromUtf8(key);
+ QVariant v;
+
+ // json_is_object(const json_t *json)
+ // json_is_array(const json_t *json)
+ // json_is_string(const json_t *json)
+ // json_is_integer(const json_t *json)
+ // json_is_real(const json_t *json)
+ // json_is_true(const json_t *json)
+ // json_is_false(const json_t *json)
+ // json_is_null(const json_t *json)
+ if (json_is_object(value)) {
+ v = mapFromJSON(value, NULL);
+ } else if (json_is_array(value)) {
+ v = listFromJSON(value);
+ } else if (json_is_string(value)) {
+ v = QString::fromUtf8(json_string_value(value));
+ } else if (json_is_integer(value)) {
+ v = json_integer_value(value);
+ } else if (json_is_real(value)) {
+ v = json_real_value(value);
+ } else if (json_is_boolean(value)) {
+ v = json_is_true(value);
+ }
+
+ if (v.isValid()) {
+ dict[k] = v;
+ }
+ }
+ return dict;
+}
+
+QString mapToJson(QMap<QString, QVariant> map)
+{
+ json_t *object = NULL;
+ char *info = NULL;
+ object = json_object();
+
+ Q_FOREACH (const QString &k, map.keys()) {
+ QVariant v = map.value(k);
+ switch (v.type()) {
+ case QVariant::String:
+ json_object_set_new(object, toCStr(k), json_string(toCStr(v.toString())));
+ break;
+ case QVariant::Int:
+ json_object_set_new(object, toCStr(k), json_integer(v.toInt()));
+ break;
+ // TODO: support other types
+ default:
+ continue;
+ }
+ }
+
+ info = json_dumps(object, 0);
+ QString ret = QString::fromUtf8(info);
+ json_decref (object);
+ free (info);
+ return ret;
+}
+
+QString translateCommitTime(qint64 timestamp, bool hours_and_minutes) {
+ timestamp *= 1000; // use milli seconds
+ qint64 now = QDateTime::currentMSecsSinceEpoch();
+ if (now <= timestamp) {
+ return QObject::tr("Just now");
+ }
+
+ qint64 delta = (now - timestamp) / 1000;
+
+ qint64 secondsPerDay = 24 * 60 * 60;
+
+ qint64 days = delta / secondsPerDay;
+ qint64 seconds = delta % secondsPerDay;
+
+ QDateTime dt = QDateTime::fromMSecsSinceEpoch(timestamp);
+
+ if (hours_and_minutes) {
+ return dt.toString("yyyy-MM-dd HH:mm");
+ }
+
+ if (days >= 14) {
+ return dt.toString("yyyy-MM-dd");
+
+ } else if (days > 0) {
+ return days == 1 ? QObject::tr("1 day ago") : QObject::tr("%1 days ago").arg(days);
+
+ } else if (seconds >= 60 * 60) {
+ qint64 hours = seconds / 3600;
+ return hours == 1 ? QObject::tr("1 hour ago") : QObject::tr("%1 hours ago").arg(hours);
+
+ } else if (seconds >= 60) {
+ qint64 minutes = seconds / 60;
+ return minutes == 1 ? QObject::tr("1 minute ago") : QObject::tr("%1 minutes ago").arg(minutes);
+
+ } else if (seconds > 0) {
+ // return seconds == 1 ? QObject::tr("1 second ago") : QObject::tr("%1 seconds ago").arg(seconds);
+ return QObject::tr("Just now");
+
+ } else {
+ return QObject::tr("Just now");
+ }
+}
+
+QString readableFileSize(qint64 size)
+{
+ QString str;
+ double value = (double)size;
+ int precision = 1;
+
+ if (value < 1000) {
+ str = "B";
+ precision = 0;
+ } else if (value >= 1000 && value < 1000*1000) {
+ value = value / 1000;
+ str = "KB";
+ precision = 0;
+ } else if (value >= 1000*1000 && value < 1000*1000*1000) {
+ value = value / 1000 / 1000;
+ str = "MB";
+ } else if (value >= 1000*1000*1000) {
+ value = value / 1000 / 1000 / 1000;
+ str = "GB";
+ }
+
+ return QString::number(value, 'f', precision) + str;
+}
+
+QString readableFileSizeV2(qint64 size)
+{
+ return readableFileSize(size);
+}
+
+
+QString md5(const QString& s)
+{
+ return QCryptographicHash::hash(s.toUtf8(), QCryptographicHash::Md5).toHex();
+}
+
+QUrl urlJoin(const QUrl& head, const QString& tail)
+{
+ QString a = head.toString();
+ QString b = tail;
+
+ if (!a.endsWith("/")) {
+ a += "/";
+ }
+ while (b.startsWith("/")) {
+ b = b.mid(1);
+ }
+ return QUrl(a + b);
+}
+
+void removeDirRecursively(const QString &path)
+{
+ QFileInfo file_info(path);
+ if (file_info.isDir()) {
+ QDir dir(path);
+ QStringList file_list = dir.entryList();
+ for (int i = 0; i < file_list.count(); ++i) {
+ removeDirRecursively(file_list.at(i));
+ }
+ removeDirRecursively(path);
+ } else {
+ QFile::remove(path);
+ }
+}
+
+QString dumpHexPresentation(const QByteArray &bytes)
+{
+ if (bytes.size() < 2)
+ return QString(bytes).toUpper();
+ QString output((char)bytes[0]);
+ output += (char)bytes[1];
+ for (int i = 2 ; i != bytes.size() ; i++) {
+ if (i % 2 == 0)
+ output += ':';
+ output += (char)bytes[i];
+ }
+ return output.toUpper();
+}
+
+QString dumpCipher(const QSslCipher &cipher)
+{
+ QString s = "\n";
+ s += "Authentication: " + cipher.authenticationMethod() + "\n";
+ s += "Encryption: " + cipher.encryptionMethod() + "\n";
+ s += "Key Exchange: " + cipher.keyExchangeMethod() + "\n";
+ s += "Cipher Name: " + cipher.name() + "\n";
+ s += "Protocol: " + cipher.protocolString() + "\n";
+ s += "Supported Bits: " + QString(cipher.supportedBits()) + "\n";
+ s += "Used Bits: " + QString(cipher.usedBits()) + "\n";
+ return s;
+}
+
+QString dumpCertificate(const QSslCertificate &cert)
+{
+ if (cert.isNull())
+ return "\n-\n";
+
+ QString s = "\n";
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ s += cert.toText();
+#else
+ QString s_none = QObject::tr("<Not Part of Certificate>");
+ #define CERTIFICATE_STR(x) ( ((x) == "" ) ? s_none : (x) )
+
+ s += "Certificate:\n";
+ s += "\nIssued To:\n";
+ s += "CommonName(CN): " + CERTIFICATE_STR(cert.subjectInfo(QSslCertificate::CommonName)) + "\n";
+ s += "Organization(O): " + CERTIFICATE_STR(cert.subjectInfo(QSslCertificate::Organization)) + "\n";
+ s += "OrganizationalUnitName(OU): " + CERTIFICATE_STR(cert.subjectInfo(QSslCertificate::OrganizationalUnitName)) + "\n";
+ s += "Serial Number: " + dumpHexPresentation(cert.serialNumber()) + "\n";
+
+ s += "\nIssued By:\n";
+ s += "CommonName(CN): " + CERTIFICATE_STR(cert.issuerInfo(QSslCertificate::CommonName)) + "\n";
+ s += "Organization(O): " + CERTIFICATE_STR(cert.issuerInfo(QSslCertificate::Organization)) + "\n";
+ s += "OrganizationalUnitName(OU): " + CERTIFICATE_STR(cert.issuerInfo(QSslCertificate::OrganizationalUnitName)) + "\n";
+
+ s += "\nPeriod Of Validity\n";
+ s += "Begins On: " + cert.effectiveDate().toString() + "\n";
+ s += "Expires On: " + cert.expiryDate().toString() + "\n";
+ s += "IsValid: " + (cert.isValid() ? QString("Yes") : QString("No")) + "\n";
+
+ s += "\nFingerprints\n";
+ s += "SHA1 Fingerprint:\n" + dumpCertificateFingerprint(cert, QCryptographicHash::Sha1) + "\n";
+ s += "MD5 Fingerprint:\n" + dumpCertificateFingerprint(cert, QCryptographicHash::Md5) + "\n";
+#endif
+
+ s += "\n\n";
+ s += cert.toPem();
+
+ return s;
+}
+
+QString dumpCertificateFingerprint(const QSslCertificate &cert, const QCryptographicHash::Algorithm &algorithm)
+{
+ if(cert.isNull())
+ return "";
+ return dumpHexPresentation(cert.digest(algorithm).toHex());
+}
+
+QString dumpSslErrors(const QList<QSslError> &errors)
+{
+ QString s;
+ foreach (const QSslError &error, errors) {
+ s += error.errorString() + "\n";
+ }
+ return s;
+}
+
+void msleep(int mseconds)
+{
+#ifdef Q_OS_WIN32
+ ::Sleep(mseconds);
+#else
+ struct timespec ts;
+ ts.tv_sec = mseconds / 1000;
+ ts.tv_nsec = mseconds % 1000 * 1000 * 1000;
+
+ int r;
+ do {
+ r = ::nanosleep(&ts, &ts);
+ } while (r == -1 && errno == EINTR);
+#endif
+}
+
+QUrl includeQueryParams(const QUrl& url,
+ const QHash<QString, QString>& params)
+{
+ QUrl u(url);
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ QUrlQuery query;
+ Q_FOREACH (const QString& key, params.keys()) {
+ QString value = params[key];
+ query.addQueryItem(QUrl::toPercentEncoding(key),
+ QUrl::toPercentEncoding(value));
+ }
+ u.setQuery(query);
+#else
+ Q_FOREACH (const QString& key, params.keys()) {
+ QString value = params[key];
+ u.addEncodedQueryItem(QUrl::toPercentEncoding(key),
+ QUrl::toPercentEncoding(value));
+ }
+#endif
+ return u;
+}
+
+QByteArray buildFormData(const QHash<QString, QString>& params)
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ QUrlQuery query;
+ Q_FOREACH (const QString& key, params.keys()) {
+ QString value = params[key];
+ query.addQueryItem(QUrl::toPercentEncoding(key),
+ QUrl::toPercentEncoding(value));
+
+ }
+ return query.query(QUrl::FullyEncoded).toUtf8();
+#else
+ QUrl u;
+ Q_FOREACH (const QString& key, params.keys()) {
+ QString value = params[key];
+ u.addEncodedQueryItem(QUrl::toPercentEncoding(key),
+ QUrl::toPercentEncoding(value));
+ }
+ return u.encodedQuery();
+#endif
+}
+
+int digitalCompare(const QString &left, const QString &right)
+{
+ int ret = 0;
+ if (left.compare(right, Qt::CaseInsensitive) == 0)
+ return ret;
+ if (left.size() == 0)
+ return -1;
+ if (right.size() == 0)
+ return 1;
+
+ QString left_sub = left;
+ QString right_sub = right;
+ const uint min_size = left.size() < right.size()
+ ? left.size() : right.size();
+ uint i;
+ for (i = 0; i != min_size; i++) {
+ if (left[i].isDigit() && right[i].isDigit())
+ break;
+ if (left[i] != right[i])
+ return left.compare(right, Qt::CaseInsensitive);
+ }
+ left_sub = left_sub.right(left_sub.size() - i);
+ right_sub = right_sub.right(right_sub.size() - i);
+
+ const QRegExp left_digit_pattern("(\\d+)*");
+ const QRegExp right_digit_pattern("(\\d+)*");
+ const int left_pos = left_digit_pattern.indexIn(left_sub);
+ const int right_pos = right_digit_pattern.indexIn(right_sub);
+ if (left_pos == 0 && right_pos == 0) {
+ quint64 left_digit = left_digit_pattern.cap(1).toUInt();
+ quint64 right_digit = right_digit_pattern.cap(1).toUInt();
+ if (left_digit == right_digit) {
+ left_sub = left_sub.right(left_sub.size() -
+ left_digit_pattern.cap(1).size());
+ right_sub = right_sub.right(right_sub.size() -
+ right_digit_pattern.cap(1).size());
+ return digitalCompare(left_sub, right_sub);
+ }
+ return left_digit - right_digit;
+ }
+ return left.compare(right, Qt::CaseInsensitive);
+}
+
+bool shouldUseFramelessWindow()
+{
+ static int _shouldUseFramelessWindow = -1;
+
+ if (_shouldUseFramelessWindow < 0) {
+ _shouldUseFramelessWindow = 1;
+#if defined(Q_OS_MAC)
+ _shouldUseFramelessWindow = 0;
+#elif defined(Q_OS_WIN32)
+ if (utils::win::isWindows10OrHigher()) {
+ _shouldUseFramelessWindow = 0;
+ }
+#endif
+ }
+
+ return _shouldUseFramelessWindow > 0;
+}
--- /dev/null
+#ifndef SEAFILE_CLIENT_UTILS_H_
+#define SEAFILE_CLIENT_UTILS_H_
+
+#include <jansson.h>
+#include <QString>
+#include <QDir>
+#include <QMap>
+#include <QHash>
+#include <QUrl>
+#include <QSslError>
+
+class QSslCipher;
+class QSslCertificate;
+
+#define toCStr(_s) ((_s).isNull() ? NULL : (_s).toUtf8().data())
+
+#if defined(XCODE_APP)
+#define RESOURCE_PATH(_name) (QDir(QCoreApplication::applicationDirPath()).filePath(QString("../Resources/")+(_name)))
+#else
+#define RESOURCE_PATH(_name) (_name)
+#endif
+
+struct sqlite3;
+struct sqlite3_stmt;
+
+typedef bool (*SqliteRowFunc) (sqlite3_stmt *stmt, void *data);
+
+sqlite3_stmt *sqlite_query_prepare (sqlite3 *db, const char *sql);
+
+int sqlite_query_exec (sqlite3 *db, const char *sql);
+
+int sqlite_foreach_selected_row (sqlite3 *db, const char *sql,
+ SqliteRowFunc callback, void *data);
+
+int checkdir_with_mkdir (const char *dir);
+
+int get_seafile_auto_start();
+
+int set_seafile_auto_start(bool on);
+
+int set_seafile_dock_icon_style(bool hidden);
+
+typedef bool (*KeyValueFunc) (void *data, const char *key,
+ const char *value);
+
+bool parse_key_value_pairs (char *string, KeyValueFunc func, void *data);
+
+QString getBrand();
+
+QString translateCommitTime(qint64 timestamp, bool hours_and_minutes = false);
+
+QString readableFileSize(qint64 size);
+
+QString readableFileSizeV2(qint64 size);
+
+QMap<QString, QVariant> mapFromJSON(json_t *json, json_error_t *error);
+QString mapToJson(QMap<QString, QVariant> map);
+
+QString defaultCcnetDir();
+
+QString defaultDownloadDir();
+
+// open file use native default file handler, return false if failed
+bool openInNativeExtension(const QString &path);
+
+// open file and select it in native file browser, return false if failed
+bool showInGraphicalShell(const QString& path);
+
+QString md5(const QString& s);
+
+QUrl urlJoin(const QUrl& url, const QString& tail);
+
+void removeDirRecursively(const QString &path);
+
+QString dumpHexPresentation(const QByteArray &bytes);
+
+QString dumpSslErrors(const QList<QSslError>&);
+
+QString dumpCipher(const QSslCipher &cipher);
+
+QString dumpCertificate(const QSslCertificate &cert);
+
+QString dumpCertificateFingerprint(const QSslCertificate &cert,
+ const QCryptographicHash::Algorithm &algorithm = QCryptographicHash::Md5);
+
+void msleep(int mseconds);
+
+
+QUrl includeQueryParams(const QUrl& url,
+ const QHash<QString, QString>& params);
+
+QByteArray buildFormData(const QHash<QString, QString>& params);
+
+int digitalCompare(const QString &left, const QString &right);
+
+bool shouldUseFramelessWindow();
+
+#endif
--- /dev/null
+#include "test_file-utils.h"
+#include <QtTest/QtTest>
+
+#include "../src/utils/file-utils.h"
+
+void FileUtils::getParentPath() {
+ using ::getParentPath;
+ QCOMPARE(getParentPath("/"), QString("/"));
+ QCOMPARE(getParentPath("//"), QString("/"));
+ QCOMPARE(getParentPath("/usr"), QString("/"));
+ QCOMPARE(getParentPath("/usr/"), QString("/"));
+ QCOMPARE(getParentPath("/usr/bin"), QString("/usr"));
+ QCOMPARE(getParentPath("/usr/bin/"), QString("/usr"));
+ QCOMPARE(getParentPath("/usr.complicate"), QString("/"));
+ QCOMPARE(getParentPath("/usr/bin.pdf"), QString("/usr"));
+ QCOMPARE(getParentPath(QString::fromUtf8("/usr/測試")), QString::fromUtf8("/usr"));
+ QCOMPARE(getParentPath(QString::fromUtf8("/√∆/測試")), QString::fromUtf8("/√∆"));
+}
+
+void FileUtils::getBaseName() {
+ using ::getBaseName;
+ QCOMPARE(getBaseName("/"), QString("/"));
+ QCOMPARE(getBaseName("//"), QString("/"));
+ QCOMPARE(getBaseName("/usr"), QString("usr"));
+ QCOMPARE(getBaseName("/usr/"), QString("usr"));
+ QCOMPARE(getBaseName("/usr/bin"), QString("bin"));
+ QCOMPARE(getBaseName("/usr/bin/"), QString("bin"));
+ QCOMPARE(getBaseName("/usr.complicate"), QString("usr.complicate"));
+ QCOMPARE(getBaseName("/usr/bin.pdf"), QString("bin.pdf"));
+ QCOMPARE(getBaseName(QString::fromUtf8("/usr/測試")), QString::fromUtf8("測試"));
+ QCOMPARE(getBaseName(QString::fromUtf8("/√∆/測試")), QString::fromUtf8("測試"));
+}
+
+void FileUtils::expandUser() {
+ using::expandUser;
+ QCOMPARE(expandUser("~"), QDir::homePath() + "/");
+ QCOMPARE(expandUser("~/"), QDir::homePath() + "/");
+ QCOMPARE(expandUser("~//testuser"), QDir::homePath() + "//testuser");
+ QCOMPARE(expandUser("~/testuser"), QDir::home().filePath("testuser"));
+ QCOMPARE(expandUser("~/testuser/test1/test2"), QDir::home().filePath("testuser/test1/test2"));
+ QCOMPARE(expandUser("~testuser"), QFileInfo(QDir::homePath()).dir().filePath("testuser") + "/");
+ QCOMPARE(expandUser("~testuser//"), QFileInfo(QDir::homePath()).dir().filePath("testuser") + "//");
+ QCOMPARE(expandUser("~testuser/test1/test2/"), QFileInfo(QDir::homePath()).dir().filePath("testuser/test1/test2") + "/");
+}
+
+QTEST_APPLESS_MAIN(FileUtils)
+
--- /dev/null
+#ifndef TESTS_FILE_UTILS_H
+#define TESTS_FILE_UTILS_H
+#include <QObject>
+
+class FileUtils : public QObject {
+ Q_OBJECT
+public:
+ virtual ~FileUtils() {};
+
+private slots:
+ void getParentPath();
+ void getBaseName();
+ void expandUser();
+};
+
+#endif // TESTS_FILE_UTILS_H
+
--- /dev/null
+#include "test_server-info.h"
+#include <QSet>
+#include <QtTest/QtTest>
+
+#include "../src/api/server-info.h"
+
+void ServerInfoTest::testFeature() {
+ ServerInfo info1;
+ QString feature1 = "file-search,office-preview,seafile-pro";
+ info1.parseFeatureFromStrings(feature1.split(','));
+ QVERIFY(info1.proEdition);
+ QVERIFY(info1.fileSearch);
+ QVERIFY(info1.officePreview);
+ QSet<QString> info1_set = feature1.split(',').toSet();
+ QSet<QString> info1b_set = info1.getFeatureStrings().toSet();
+ QCOMPARE(info1_set, info1b_set);
+
+ ServerInfo info2;
+ QString feature2 = "file-search,seafile-pro";
+ info2.parseFeatureFromStrings(feature2.split(','));
+ QVERIFY(info2.proEdition);
+ QVERIFY(info2.fileSearch);
+ QVERIFY(!info2.officePreview);
+ QSet<QString> info2_set = feature2.split(',').toSet();
+ QSet<QString> info2b_set = info2.getFeatureStrings().toSet();
+ QCOMPARE(info2_set, info2b_set);
+
+ ServerInfo info3;
+ QString feature3 = "file-search,office-preview,seafile-pro";
+ info3.parseFeatureFromStrings(feature3.split(','));
+ QVERIFY(info3.proEdition);
+ QVERIFY(info3.fileSearch);
+ QVERIFY(info3.officePreview);
+ QSet<QString> info3_set = feature3.split(',').toSet();
+ QSet<QString> info3b_set = info3.getFeatureStrings().toSet();
+ QCOMPARE(info3_set, info3b_set);
+
+ info3.parseFeatureFromString("office-preview", false);
+ QVERIFY(!info3.officePreview);
+}
+
+void ServerInfoTest::testVersion() {
+ ServerInfo info;
+ QString version = "1.2.4";
+ info.parseVersionFromString(version);
+ QCOMPARE(info.majorVersion, 1u);
+ QCOMPARE(info.minorVersion, 2u);
+ QCOMPARE(info.patchVersion, 4u);
+ QCOMPARE(info.getVersionString(), version);
+}
+
+QTEST_APPLESS_MAIN(ServerInfoTest)
--- /dev/null
+#ifndef TESTS_SERVER_INFO_H
+#define TESTS_SERVER_INFO_H
+#include <QObject>
+
+class ServerInfoTest : public QObject {
+ Q_OBJECT
+public:
+ virtual ~ServerInfoTest() {};
+
+private slots:
+ void testFeature();
+ void testVersion();
+};
+
+#endif // TESTS_SERVER_INFO_H
+
--- /dev/null
+#include "test_stl.h"
+#include <QSet>
+#include <QtTest/QtTest>
+#include <vector>
+#include <cstring>
+#include <cwchar>
+
+#include "../src/utils/stl.h"
+
+void STLTest::testBufferArry() {
+ using utils::BufferArray;
+ // constructor
+ std::string test1("123456789abcdefg");
+ BufferArray buffer(test1);
+ QVERIFY(test1.size() + 1 == buffer.size());
+ QVERIFY(buffer.capacity() == buffer.size());
+ QVERIFY(strncmp(test1.data(), buffer.data(), test1.size()) == 0);
+
+ // operator[]
+ QVERIFY(test1[0] == '1');
+ QVERIFY(test1[1] == '2');
+ QVERIFY(test1[2] == '3');
+
+ // reserve
+ buffer.resize(30);
+ QVERIFY(buffer.capacity() == 30);
+
+ // shrink_to_fit
+ buffer.shrink_to_fit();
+ QVERIFY(buffer.capacity() == buffer.size());
+
+ // resize
+ buffer.resize(9);
+ std::string test2("12345678");
+ QVERIFY(test2.size() + 1 == buffer.size());
+ QVERIFY(buffer.capacity() > buffer.size());
+ QVERIFY(strncmp(test2.data(), buffer.data(), test2.size()) == 0);
+
+ // shrink_to_fit
+ buffer.shrink_to_fit();
+ QVERIFY(buffer.capacity() == buffer.size());
+
+#ifdef UTILS_CXX11_MODE
+ // move
+ std::string test3("gqjdiw913abc_123d");
+ BufferArray other_buffer(test3);
+ buffer = std::move(other_buffer);
+ QVERIFY(test3.size() + 1 == buffer.size());
+ QVERIFY(buffer.capacity() == buffer.size());
+ QVERIFY(strncmp(test3.data(), buffer.data(), test3.size()) == 0);
+
+ // constructor2
+ const char test_string[] = "abcdefg";
+ size_t test_size = sizeof(test_string);
+ buffer = BufferArray(test_string);
+ QVERIFY(test_size == buffer.size());
+ QVERIFY(buffer.capacity() == buffer.size());
+ QVERIFY(memcmp(test_string, buffer.data(), test_size) == 0);
+#endif
+}
+
+void STLTest::testWBufferArry() {
+ using utils::WBufferArray;
+ // constructor
+ std::wstring test1(L"123456789abcdefg");
+ WBufferArray buffer(test1);
+ QVERIFY(test1.size() + 1 == buffer.size());
+ QVERIFY(buffer.capacity() == buffer.size());
+ QVERIFY(wcsncmp(test1.data(), buffer.data(), test1.size()) == 0);
+
+ // operator[]
+ QVERIFY(test1[0] == L'1');
+ QVERIFY(test1[1] == L'2');
+ QVERIFY(test1[2] == L'3');
+
+ // reserve
+ buffer.resize(30);
+ QVERIFY(buffer.capacity() == 30);
+
+ // shrink_to_fit
+ buffer.shrink_to_fit();
+ QVERIFY(buffer.capacity() == buffer.size());
+
+ // resize
+ buffer.resize(9);
+ std::wstring test2(L"12345678");
+ QVERIFY(test2.size() + 1 == buffer.size());
+ QVERIFY(buffer.capacity() > buffer.size());
+ QVERIFY(wcsncmp(test2.data(), buffer.data(), test2.size()) == 0);
+
+#ifdef UTILS_CXX11_MODE
+ // move
+ std::wstring test3(L"gqjdiw913abc_123d");
+ WBufferArray other_buffer(test3);
+ buffer = std::move(other_buffer);
+ QVERIFY(test3.size() + 1 == buffer.size());
+ QVERIFY(buffer.capacity() == buffer.size());
+ QVERIFY(wcsncmp(test3.data(), buffer.data(), test3.size()) == 0);
+
+ // constructor2
+ const wchar_t test_string[] = L"abcdefg";
+ size_t test_size = sizeof(test_string) / sizeof(wchar_t);
+ buffer = WBufferArray(test_string);
+ QVERIFY(test_size == buffer.size());
+ QVERIFY(buffer.capacity() == buffer.size());
+ QVERIFY(memcmp(test_string, buffer.data(), test_size) == 0);
+#endif
+}
+
+
+QTEST_APPLESS_MAIN(STLTest)
--- /dev/null
+#ifndef TESTS_STL_H
+#define TESTS_STL_H
+#include <QObject>
+
+class STLTest : public QObject {
+ Q_OBJECT
+public:
+ virtual ~STLTest() {};
+
+private slots:
+ void testBufferArry();
+ void testWBufferArry();
+};
+
+#endif // TESTS_STL_H
+
--- /dev/null
+#include "test_utils.h"
+#include <QtTest/QtTest>
+#include <algorithm> // std::sort
+
+#include "../src/utils/utils.h"
+
+namespace {
+
+bool digitalCompareFileByName(const QString& a, const QString& b)
+{
+ return digitalCompare(a, b) < 0 ? true : false;
+}
+
+} // namespace
+
+void Utils::testReadableFileSize() {
+ QCOMPARE(::readableFileSize(0), QString("0B"));
+ QCOMPARE(::readableFileSize(1000), QString("1KB"));
+ QCOMPARE(::readableFileSize(1500), QString("2KB"));
+ QCOMPARE(::readableFileSize(1000000), QString("1.0MB"));
+ QCOMPARE(::readableFileSize(1230000), QString("1.2MB"));
+ QCOMPARE(::readableFileSize(1000 * 1000 * 1000), QString("1.0GB"));
+ QCOMPARE(::readableFileSize(1100 * 1000 * 1000), QString("1.1GB"));
+}
+
+
+void Utils::testIncludeUrlParams() {
+ QUrl urla(QString("http://example.com"));
+
+ QHash<QString, QString> params;
+ params.insert("simple", "c");
+ params.insert("withspecial", "a?b");
+ params.insert("withspace", "a b");
+ params.insert("username", "a123fx b");
+ params.insert("password", "!@#+-$%^12&*()qweqesaf\"';`~");
+ params.insert("withplus", "a+b");
+
+ QUrl urlb = ::includeQueryParams(urla, params);
+
+ QCOMPARE(urla.scheme(), urlb.scheme());
+ QCOMPARE(urla.host(), urlb.host());
+
+ Q_FOREACH (const QString& key, params.keys()) {
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
+ QString encoded_key = QUrl::toPercentEncoding(key);
+ QString encoded_value = QUrl::toPercentEncoding(params[encoded_key]);
+ QUrlQuery query = QUrlQuery(urlb.query());
+ QCOMPARE(query.queryItemValue(encoded_key, QUrl::FullyEncoded), encoded_value);
+#else
+ QCOMPARE(urlb.queryItemValue(key), params[key]);
+#endif
+ }
+}
+
+void Utils::testDigitalCompare() {
+ QList<QString> list;
+ list << "05 copy 2.ico" << "05 copy 3.ico"
+ << "05 copy.ico" << "05.ico"
+ << "34th TOPIK Papers - Advanced level 2.pdf"
+ << "34th TOPIK Papers - Advanced level.pdf"
+ << "A1/" << "B1/" << "a2/" << "b2/"
+ << "IMG_20140523_171911 - 副本.jpg"
+ << "IMG_20140523_171911.jpg"
+ << "MIT18_06SCF11_Ses3.1sum.pdf" << "Paraffin.exe"
+ << "Screen Shot 2016-08-13 at 11.42.35 PM.png"
+ << "Screen Shot 2016-09-02 at 4.47.12 PM.png"
+ << "WixDependencyExtension.dll"
+ << "darice - 副本 - 副本.cub"
+ << "darice - 副本.cub" << "darice.cub"
+ << "depends.chm" << "depends.exe"
+ << "dokan-build - 副本.log" << "dokan-build.log"
+ << "dokan-build copy 2 - 副本(2).log"
+ << "dokan-build copy 2 - 副本.log"
+ << "dokan-build copy 2.log"
+ << "dokan-build copy 3.log"
+ << "dokan-build copy.log"
+ << "heat.exe" << "heat.exe.config"
+ << "new copy.txt" << "new.txt"
+ << "require(1).js" << "require.js"
+ << "subfolder1/" << "untitled folder/"
+ << "whole-stage-codegen.pdf" << "wix.dll"
+ << "x copy 10.md" << "x copy.md"
+ << "x copy 2.md" << "x copy 3.md"
+ << "新建文本文档.txt"
+ << "新建文本文档 copy.txt"
+ << "新建文本文档 - 副本.txt"
+ << "新建文本文档(2).txt"
+ << "新建文本文档(3).txt";
+ std::sort(list.begin(), list.end(), digitalCompareFileByName);
+
+ QCOMPARE(::digitalCompare("9", "9"), 0);
+ QCOMPARE(::digitalCompare("aa9aa", "aa9aa"), 0);
+ QCOMPARE(::digitalCompare("99a99", "99a99"), 0);
+ QCOMPARE(::digitalCompare("9", "11"), -2);
+ QCOMPARE(::digitalCompare("1.9", "1.11"), -2);
+ QCOMPARE(::digitalCompare("1 9", "1 11"), -2);
+ QCOMPARE(::digitalCompare("1abc1", "1abc1.abc"), -1);
+ QCOMPARE(::digitalCompare("1.1.1.1.9", "1.1.1.1.11"), -2);
+ QCOMPARE(::digitalCompare("a9", "a11"), -2);
+ QCOMPARE(::digitalCompare("a9aaa", "a11aaa"), -2);
+ QCOMPARE(::digitalCompare("zzz9", "bbb11"), QString::compare("zzz9", "bbb11"));
+ QCOMPARE(::digitalCompare("pp9p", "pa11a"), QString::compare("pp9p", "pa11a"));
+}
+
+QTEST_APPLESS_MAIN(Utils)
--- /dev/null
+#ifndef TESTS_UTILS_H
+#define TESTS_UTILS_H
+#include <QObject>
+
+class Utils : public QObject {
+ Q_OBJECT
+public:
+ virtual ~Utils() {};
+
+private slots:
+ void testReadableFileSize();
+ void testIncludeUrlParams();
+ void testDigitalCompare();
+};
+
+#endif // TESTS_UTILS_H
+
--- /dev/null
+/**
+ * QtAwesome - use font-awesome (or other font icons) in your c++ / Qt Application
+ *
+ * Copyright 2013 - Reliable Bits Software by Blommers IT. All Rights Reserved.
+ * Author Rick Blommers
+ */
+
+#include "QtAwesome.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QFontDatabase>
+
+
+/// The font-awesome icon painter
+class QtAwesomeCharIconPainter: public QtAwesomeIconPainter
+{
+public:
+ virtual void paint( QtAwesome* awesome, QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state, const QVariantMap& options )
+ {
+ Q_UNUSED(mode);
+ Q_UNUSED(state);
+ Q_UNUSED(options);
+
+ painter->save();
+
+ // set the correct color
+ QColor color = options.value("color").value<QColor>();
+ QString text = options.value("text").toString();
+
+ if( mode == QIcon::Disabled ) {
+ color = options.value("color-disabled").value<QColor>();
+ QVariant alt = options.value("text-disabled");
+ if( alt.isValid() ) {
+ text = alt.toString();
+ }
+ } else if( mode == QIcon::Active ) {
+ color = options.value("color-active").value<QColor>();
+ QVariant alt = options.value("text-active");
+ if( alt.isValid() ) {
+ text = alt.toString();
+ }
+ } else if( mode == QIcon::Selected ) {
+ color = options.value("color-selected").value<QColor>();
+ QVariant alt = options.value("text-selected");
+ if( alt.isValid() ) {
+ text = alt.toString();
+ }
+ }
+ painter->setPen(color);
+
+ // add some 'padding' around the icon
+ int drawSize = qRound(rect.height()*options.value("scale-factor").toFloat());
+
+ painter->setFont( awesome->font(drawSize) );
+ painter->drawText( rect, text, QTextOption( Qt::AlignCenter|Qt::AlignVCenter ) );
+ painter->restore();
+ }
+
+};
+
+
+//---------------------------------------------------------------------------------------
+
+
+/// The painter icon engine.
+class QtAwesomeIconPainterIconEngine : public QIconEngine
+{
+
+public:
+
+ QtAwesomeIconPainterIconEngine( QtAwesome* awesome, QtAwesomeIconPainter* painter, const QVariantMap& options )
+ : awesomeRef_(awesome)
+ , iconPainterRef_(painter)
+ , options_(options)
+ {
+ }
+
+ virtual ~QtAwesomeIconPainterIconEngine() {}
+
+ QtAwesomeIconPainterIconEngine* clone() const
+ {
+ return new QtAwesomeIconPainterIconEngine( awesomeRef_, iconPainterRef_, options_ );
+ }
+
+ virtual void paint(QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state)
+ {
+ Q_UNUSED( mode );
+ Q_UNUSED( state );
+ iconPainterRef_->paint( awesomeRef_, painter, rect, mode, state, options_ );
+ }
+
+ virtual QPixmap pixmap(const QSize& size, QIcon::Mode mode, QIcon::State state)
+ {
+ QPixmap pm(size);
+ pm.fill( Qt::transparent ); // we need transparency
+ {
+ QPainter p(&pm);
+ paint(&p, QRect(QPoint(0,0),size), mode, state);
+ }
+ return pm;
+ }
+
+private:
+
+ QtAwesome* awesomeRef_; ///< a reference to the QtAwesome instance
+ QtAwesomeIconPainter* iconPainterRef_; ///< a reference to the icon painter
+ QVariantMap options_; ///< the options for this icon painter
+};
+
+
+//---------------------------------------------------------------------------------------
+
+/// The default icon colors
+QtAwesome::QtAwesome( QObject* parent )
+ : QObject( parent )
+ , namedCodepoints_()
+{
+ // initialize the default options
+ setDefaultOption( "color", QColor(50,50,50) );
+ setDefaultOption( "color-disabled", QColor(70,70,70,60));
+ setDefaultOption( "color-active", QColor(10,10,10));
+ setDefaultOption( "color-selected", QColor(10,10,10));
+ setDefaultOption( "scale-factor", 0.9 );
+
+ setDefaultOption( "text", QVariant() );
+ setDefaultOption( "text-disabled", QVariant() );
+ setDefaultOption( "text-active", QVariant() );
+ setDefaultOption( "text-selected", QVariant() );
+
+ fontIconPainter_ = new QtAwesomeCharIconPainter();
+
+}
+
+
+QtAwesome::~QtAwesome()
+{
+ delete fontIconPainter_;
+// delete errorIconPainter_;
+ qDeleteAll(painterMap_);
+}
+
+/// initializes the QtAwesome icon factory with the given fontname
+void QtAwesome::init(const QString& fontname)
+{
+ fontName_ = fontname;
+}
+
+
+/// a specialized init function so font-awesome is loaded and initialized
+/// this method return true on success, it will return false if the fnot cannot be initialized
+/// To initialize QtAwesome with font-awesome you need to call this method
+bool QtAwesome::initFontAwesome( )
+{
+ static int fontAwesomeFontId = -1;
+
+ // only load font-awesome once
+ if( fontAwesomeFontId < 0 ) {
+
+ // The macro below internally calls "qInitResources_QtAwesome()". this initializes
+ // the resource system. For a .pri project this isn't required, but when building and using a
+ // static library the resource need to initialized first.
+ ///
+ // I've checked th qInitResource_* code and calling this method mutliple times shouldn't be any problem
+ // (More info about this subject: http://qt-project.org/wiki/QtResources)
+ Q_INIT_RESOURCE(QtAwesome);
+
+ // load the font file
+ QFile res(":/fonts/fontawesome.ttf");
+ if(!res.open(QIODevice::ReadOnly)) {
+ qDebug() << "Font awesome font could not be loaded!";
+ return false;
+ }
+ QByteArray fontData( res.readAll() );
+ res.close();
+
+ // fetch the given font
+ fontAwesomeFontId = QFontDatabase::addApplicationFontFromData(fontData);
+ }
+
+ QStringList loadedFontFamilies = QFontDatabase::applicationFontFamilies(fontAwesomeFontId);
+ if( !loadedFontFamilies.empty() ) {
+ fontName_= loadedFontFamilies.at(0);
+ } else {
+ qDebug() << "Font awesome font is empty?!";
+ fontAwesomeFontId = -1; // restore the font-awesome id
+ return false;
+ }
+
+ // intialize the map
+ QHash<QString, int>& m = namedCodepoints_;
+ m.insert( "glass", icon_glass );
+ m.insert( "music", icon_music );
+ m.insert( "search", icon_search );
+ m.insert( "envelope", icon_envelope );
+ m.insert( "heart", icon_heart );
+ m.insert( "star", icon_star );
+ m.insert( "star-empty", icon_star_empty );
+ m.insert( "user", icon_user );
+ m.insert( "film", icon_film );
+ m.insert( "th-large", icon_th_large );
+ m.insert( "th", icon_th );
+ m.insert( "th-list", icon_th_list );
+ m.insert( "ok", icon_ok );
+ m.insert( "remove", icon_remove );
+ m.insert( "zoom-in", icon_zoom_in );
+
+ m.insert( "zoom-out", icon_zoom_out );
+ m.insert( "off", icon_off );
+ m.insert( "signal", icon_signal );
+ m.insert( "cog", icon_cog );
+ m.insert( "gear", icon_gear );
+ m.insert( "trash", icon_trash );
+ m.insert( "home", icon_home );
+ m.insert( "file_alt", icon_file_alt );
+ m.insert( "time", icon_time );
+ m.insert( "road", icon_road );
+ m.insert( "download-alt", icon_download_alt );
+ m.insert( "download", icon_download );
+ m.insert( "upload", icon_upload );
+ m.insert( "inbox", icon_inbox );
+ m.insert( "play-circle", icon_play_circle );
+ m.insert( "repeat", icon_repeat );
+
+ /* \f020 doesn't work in Safari. all shifted one down */
+
+
+ m.insert( "refresh", icon_refresh );
+ m.insert( "list-alt", icon_list_alt );
+ m.insert( "lock", icon_lock );
+ m.insert( "flag", icon_flag );
+ m.insert( "headphones", icon_headphones );
+ m.insert( "volume-off", icon_volume_off );
+ m.insert( "volume-down", icon_volume_down );
+ m.insert( "volume-up", icon_volume_up );
+ m.insert( "qrcode", icon_qrcode );
+ m.insert( "barcode", icon_barcode );
+ m.insert( "tag", icon_tag );
+ m.insert( "tags", icon_tags );
+ m.insert( "book", icon_book );
+ m.insert( "bookmark", icon_bookmark );
+ m.insert( "print", icon_print );
+
+ m.insert( "camera", icon_camera );
+ m.insert( "font", icon_font );
+ m.insert( "bold", icon_bold );
+ m.insert( "italic", icon_italic );
+ m.insert( "text-height", icon_text_height );
+ m.insert( "text-width", icon_text_width );
+ m.insert( "align-left", icon_align_left );
+ m.insert( "align-center", icon_align_center );
+ m.insert( "align-right", icon_align_right );
+ m.insert( "align-justify", icon_align_justify );
+ m.insert( "list", icon_list );
+ m.insert( "indent-left", icon_indent_left );
+ m.insert( "indent-right", icon_indent_right );
+ m.insert( "facetime-video", icon_facetime_video );
+ m.insert( "picture", icon_picture );
+
+ m.insert( "pencil", icon_pencil );
+ m.insert( "map-marker", icon_map_marker );
+ m.insert( "adjust", icon_adjust );
+ m.insert( "tint", icon_tint );
+ m.insert( "edit", icon_edit );
+ m.insert( "share", icon_share );
+ m.insert( "check", icon_check );
+ m.insert( "move", icon_move );
+ m.insert( "step-backward", icon_step_backward );
+ m.insert( "fast-backward", icon_fast_backward );
+ m.insert( "backward", icon_backward );
+ m.insert( "play", icon_play );
+ m.insert( "pause", icon_pause );
+ m.insert( "stop", icon_stop );
+ m.insert( "forward", icon_forward );
+
+ m.insert( "fast-forward", icon_fast_forward );
+ m.insert( "step-forward", icon_step_forward );
+ m.insert( "eject", icon_eject );
+ m.insert( "chevron-left", icon_chevron_left );
+ m.insert( "chevron-right", icon_chevron_right );
+ m.insert( "plus-sign", icon_plus_sign );
+ m.insert( "minus-sign", icon_minus_sign );
+ m.insert( "remove-sign", icon_remove_sign );
+ m.insert( "ok-sign", icon_ok_sign );
+ m.insert( "question-sign", icon_question_sign );
+ m.insert( "info-sign", icon_info_sign );
+ m.insert( "screenshot", icon_screenshot );
+ m.insert( "remove-circle", icon_remove_circle );
+ m.insert( "ok-circle", icon_ok_circle );
+ m.insert( "ban-circle", icon_ban_circle );
+
+ m.insert( "arrow-left", icon_arrow_left );
+ m.insert( "arrow-right", icon_arrow_right );
+ m.insert( "arrow-up", icon_arrow_up );
+ m.insert( "arrow-down", icon_arrow_down );
+ m.insert( "share-alt", icon_share_alt );
+ m.insert( "resize-full", icon_resize_full );
+ m.insert( "resize-small", icon_resize_small );
+ m.insert( "plus", icon_plus );
+ m.insert( "minus", icon_minus );
+ m.insert( "asterisk", icon_asterisk );
+ m.insert( "exclamation-sign", icon_exclamation_sign );
+ m.insert( "gift", icon_gift );
+ m.insert( "leaf", icon_leaf );
+ m.insert( "fire", icon_fire );
+ m.insert( "eye-open", icon_eye_open );
+
+ m.insert( "eye-close", icon_eye_close );
+ m.insert( "warning-sign", icon_warning_sign );
+ m.insert( "plane", icon_plane );
+ m.insert( "calendar", icon_calendar );
+ m.insert( "random", icon_random );
+ m.insert( "comment", icon_comment );
+ m.insert( "magnet", icon_magnet );
+ m.insert( "chevron-up", icon_chevron_up );
+ m.insert( "chevron-down", icon_chevron_down );
+ m.insert( "retweet", icon_retweet );
+ m.insert( "shopping-cart", icon_shopping_cart );
+ m.insert( "folder-close", icon_folder_close );
+ m.insert( "folder-open", icon_folder_open );
+ m.insert( "resize-vertical", icon_resize_vertical );
+ m.insert( "resize-horizontal", icon_resize_horizontal );
+
+ m.insert( "bar-chart", icon_bar_chart );
+ m.insert( "twitter-sign", icon_twitter_sign );
+ m.insert( "facebook-sign", icon_facebook_sign );
+ m.insert( "camera-retro", icon_camera_retro );
+ m.insert( "key", icon_key );
+ m.insert( "cogs", icon_cogs );
+ m.insert( "gears", icon_gears );
+ m.insert( "comments", icon_comments );
+ m.insert( "thumbs-up-alt", icon_thumbs_up_alt );
+ m.insert( "thumbs-down-alt", icon_thumbs_down_alt );
+ m.insert( "star-half", icon_star_half );
+ m.insert( "heart-empty", icon_heart_empty );
+ m.insert( "signout", icon_signout );
+ m.insert( "linkedin-sign", icon_linkedin_sign );
+ m.insert( "pushpin", icon_pushpin );
+ m.insert( "external-link", icon_external_link );
+
+ m.insert( "signin", icon_signin );
+ m.insert( "trophy", icon_trophy );
+ m.insert( "github-sign", icon_github_sign );
+ m.insert( "upload-alt", icon_upload_alt );
+ m.insert( "lemon", icon_lemon );
+ m.insert( "phone", icon_phone );
+ m.insert( "check-empty", icon_check_empty );
+ m.insert( "bookmark-empty", icon_bookmark_empty );
+ m.insert( "phone-sign", icon_phone_sign );
+ m.insert( "twitter", icon_twitter );
+ m.insert( "facebook", icon_facebook );
+ m.insert( "github", icon_github );
+ m.insert( "unlock", icon_unlock );
+ m.insert( "credit-card", icon_credit_card );
+ m.insert( "rss", icon_rss );
+
+ m.insert( "hdd", icon_hdd );
+ m.insert( "bullhorn", icon_bullhorn );
+ m.insert( "bell", icon_bell );
+ m.insert( "certificate", icon_certificate );
+ m.insert( "hand-right", icon_hand_right );
+ m.insert( "hand-left", icon_hand_left );
+ m.insert( "hand-up", icon_hand_up );
+ m.insert( "hand-down", icon_hand_down );
+ m.insert( "circle-arrow-left", icon_circle_arrow_left );
+ m.insert( "circle-arrow-right", icon_circle_arrow_right );
+ m.insert( "circle-arrow-up", icon_circle_arrow_up );
+ m.insert( "circle-arrow-down", icon_circle_arrow_down );
+ m.insert( "globe", icon_globe );
+ m.insert( "wrench", icon_wrench );
+ m.insert( "tasks", icon_tasks );
+
+ m.insert( "filter", icon_filter );
+ m.insert( "briefcase", icon_briefcase );
+ m.insert( "fullscreen", icon_fullscreen );
+
+ m.insert( "group", icon_group );
+ m.insert( "link", icon_link );
+ m.insert( "cloud", icon_cloud );
+ m.insert( "beaker", icon_beaker );
+ m.insert( "cut", icon_cut );
+ m.insert( "copy", icon_copy );
+ m.insert( "paper-clip", icon_paper_clip );
+ m.insert( "save", icon_save );
+ m.insert( "sign-blank", icon_sign_blank );
+ m.insert( "reorder", icon_reorder );
+ m.insert( "list-ul", icon_list_ul );
+ m.insert( "list-ol", icon_list_ol );
+ m.insert( "strikethrough", icon_strikethrough );
+ m.insert( "underline", icon_underline );
+ m.insert( "table", icon_table );
+
+ m.insert( "magic", icon_magic );
+ m.insert( "truck", icon_truck );
+ m.insert( "pinterest", icon_pinterest );
+ m.insert( "pinterest-sign", icon_pinterest_sign );
+ m.insert( "google-plus-sign", icon_google_plus_sign );
+ m.insert( "google-plus", icon_google_plus );
+ m.insert( "money", icon_money );
+ m.insert( "caret-down", icon_caret_down );
+ m.insert( "caret-up", icon_caret_up );
+ m.insert( "caret-left", icon_caret_left );
+ m.insert( "caret-right", icon_caret_right );
+ m.insert( "columns", icon_columns );
+ m.insert( "sort", icon_sort );
+ m.insert( "sort-down", icon_sort_down );
+ m.insert( "sort-up", icon_sort_up );
+
+ m.insert( "envelope-alt", icon_envelope_alt );
+ m.insert( "linkedin", icon_linkedin );
+ m.insert( "undo", icon_undo );
+ m.insert( "legal", icon_legal );
+ m.insert( "dashboard", icon_dashboard );
+ m.insert( "comment-alt", icon_comment_alt );
+ m.insert( "comments-alt", icon_comments_alt );
+ m.insert( "bolt", icon_bolt );
+ m.insert( "sitemap", icon_sitemap );
+ m.insert( "umbrella", icon_umbrella );
+ m.insert( "paste", icon_paste );
+ m.insert( "lightbulb", icon_lightbulb );
+ m.insert( "exchange", icon_exchange );
+ m.insert( "cloud-download", icon_cloud_download );
+ m.insert( "cloud-upload", icon_cloud_upload );
+
+ m.insert( "user-md", icon_user_md );
+ m.insert( "stethoscope", icon_stethoscope );
+ m.insert( "suitcase", icon_suitcase );
+ m.insert( "bell-alt", icon_bell_alt );
+ m.insert( "coffee", icon_coffee );
+ m.insert( "food", icon_food );
+ m.insert( "file-text-alt", icon_file_text_alt );
+ m.insert( "building", icon_building );
+ m.insert( "hospital", icon_hospital );
+ m.insert( "ambulance", icon_ambulance );
+ m.insert( "medkit", icon_medkit );
+ m.insert( "fighter-jet", icon_fighter_jet );
+ m.insert( "beer", icon_beer );
+ m.insert( "h-sign", icon_h_sign );
+ m.insert( "plus-sign-alt", icon_plus_sign_alt );
+
+ m.insert( "double-angle-left", icon_double_angle_left );
+ m.insert( "double-angle-right", icon_double_angle_right );
+ m.insert( "double-angle-up", icon_double_angle_up );
+ m.insert( "double-angle-down", icon_double_angle_down );
+ m.insert( "angle-left", icon_angle_left );
+ m.insert( "angle-right", icon_angle_right );
+ m.insert( "angle-up", icon_angle_up );
+ m.insert( "angle-down", icon_angle_down );
+ m.insert( "desktop", icon_desktop );
+ m.insert( "laptop", icon_laptop );
+ m.insert( "tablet", icon_tablet );
+ m.insert( "mobile-phone", icon_mobile_phone );
+ m.insert( "circle-blank", icon_circle_blank );
+ m.insert( "quote-left", icon_quote_left );
+ m.insert( "quote-right", icon_quote_right );
+
+ m.insert( "spinner", icon_spinner );
+ m.insert( "circle", icon_circle );
+ m.insert( "reply", icon_reply );
+ m.insert( "mail_reply", icon_mail_reply );
+
+ m.insert( "github-alt", icon_github_alt );
+ m.insert( "folder-close-alt", icon_folder_close_alt );
+ m.insert( "folder-open-alt", icon_folder_open_alt );
+
+ m.insert( "expand_alt", icon_expand_alt );
+ m.insert( "collapse_alt", icon_collapse_alt );
+ m.insert( "smile", icon_smile );
+ m.insert( "frown", icon_frown );
+ m.insert( "meh", icon_meh );
+ m.insert( "gamepad", icon_gamepad );
+ m.insert( "keyboard", icon_keyboard );
+ m.insert( "flag_alt", icon_flag_alt );
+ m.insert( "flag_checkered", icon_flag_checkered );
+
+ m.insert( "terminal", icon_terminal );
+ m.insert( "code", icon_code );
+ m.insert( "reply_all", icon_reply_all );
+ m.insert( "mail_reply_all", icon_mail_reply_all );
+ m.insert( "star_half_full", icon_star_half_full );
+ m.insert( "star_half_empty", icon_star_half_empty );
+ m.insert( "location_arrow", icon_location_arrow );
+ m.insert( "crop", icon_crop );
+ m.insert( "code_fork", icon_code_fork );
+ m.insert( "unlink", icon_unlink );
+ m.insert( "question", icon_question );
+ m.insert( "info", icon_info );
+ m.insert( "exclamation", icon_exclamation );
+ m.insert( "superscript", icon_superscript );
+ m.insert( "subscript", icon_subscript );
+ m.insert( "eraser", icon_eraser );
+ m.insert( "puzzle_piece", icon_puzzle_piece );
+
+ m.insert( "microphone", icon_microphone );
+ m.insert( "microphone_off", icon_microphone_off );
+ m.insert( "shield", icon_shield );
+ m.insert( "calendar_empty", icon_calendar_empty );
+ m.insert( "fire_extinguisher", icon_fire_extinguisher );
+ m.insert( "rocket", icon_rocket );
+ m.insert( "maxcdn", icon_maxcdn );
+ m.insert( "chevron_sign_left", icon_chevron_sign_left );
+ m.insert( "chevron_sign_right", icon_chevron_sign_right );
+ m.insert( "chevron_sign_up", icon_chevron_sign_up );
+ m.insert( "chevron_sign_down", icon_chevron_sign_down );
+ m.insert( "html5", icon_html5 );
+ m.insert( "css3", icon_css3 );
+ m.insert( "anchor", icon_anchor );
+ m.insert( "unlock_alt", icon_unlock_alt );
+
+ m.insert( "bullseye", icon_bullseye );
+ m.insert( "ellipsis_horizontal", icon_ellipsis_horizontal );
+ m.insert( "ellipsis_vertical", icon_ellipsis_vertical );
+ m.insert( "rss_sign", icon_rss_sign );
+ m.insert( "play_sign", icon_play_sign );
+ m.insert( "ticket", icon_ticket );
+ m.insert( "minus_sign_alt", icon_minus_sign_alt );
+ m.insert( "check_minus", icon_check_minus );
+ m.insert( "level_up", icon_level_up );
+ m.insert( "level_down", icon_level_down );
+ m.insert( "check_sign", icon_check_sign );
+ m.insert( "edit_sign", icon_edit_sign );
+ m.insert( "external_link_sign", icon_external_link_sign );
+ m.insert( "share_sign", icon_share_sign );
+
+ // v3.2.0
+ m.insert( "compass", icon_compass );
+
+ m.insert( "collapse", icon_collapse );
+ m.insert( "collapse_top", icon_collapse_top );
+ m.insert( "expand", icon_expand );
+ m.insert( "euro", icon_euro );
+ m.insert( "eur", icon_eur );
+ m.insert( "gbp", icon_gbp );
+ m.insert( "dollar", icon_dollar );
+ m.insert( "usd", icon_usd );
+ m.insert( "rupee", icon_rupee );
+ m.insert( "inr", icon_inr );
+ m.insert( "yen", icon_yen );
+ m.insert( "jpy", icon_jpy );
+ m.insert( "renminbi", icon_renminbi );
+ m.insert( "cny", icon_cny );
+ m.insert( "won", icon_won );
+ m.insert( "krw", icon_krw );
+ m.insert( "bitcoin", icon_bitcoin );
+ m.insert( "btc", icon_btc );
+ m.insert( "file", icon_file );
+ m.insert( "file_text", icon_file_text );
+ m.insert( "sort_by_alphabet", icon_sort_by_alphabet );
+ m.insert( "sort_by_alphabet_alt", icon_sort_by_alphabet_alt );
+ m.insert( "sort_by_attributes", icon_sort_by_attributes );
+ m.insert( "sort_by_attributes_alt", icon_sort_by_attributes_alt );
+
+ m.insert( "sort_by_order", icon_sort_by_order );
+ m.insert( "sort_by_order_alt", icon_sort_by_order_alt );
+ m.insert( "thumbs_up", icon_thumbs_up );
+ m.insert( "thumbs_down", icon_thumbs_down );
+ m.insert( "youtube_sign", icon_youtube_sign );
+ m.insert( "youtube", icon_youtube );
+ m.insert( "xing", icon_xing );
+ m.insert( "xing_sign", icon_xing_sign );
+ m.insert( "youtube_play", icon_youtube_play );
+ m.insert( "dropbox", icon_dropbox );
+ m.insert( "stackexchange", icon_stackexchange );
+ m.insert( "instagram", icon_instagram );
+ m.insert( "flickr", icon_flickr );
+
+ m.insert( "adn", icon_adn );
+ m.insert( "bitbucket", icon_bitbucket );
+ m.insert( "bitbucket_sign", icon_bitbucket_sign );
+ m.insert( "tumblr", icon_tumblr );
+ m.insert( "tumblr_sign", icon_tumblr_sign );
+ m.insert( "long_arrow_down", icon_long_arrow_down );
+ m.insert( "long_arrow_up", icon_long_arrow_up );
+ m.insert( "long_arrow_left", icon_long_arrow_left );
+ m.insert( "long_arrow_right", icon_long_arrow_right );
+ m.insert( "apple", icon_apple );
+ m.insert( "windows", icon_windows );
+ m.insert( "android", icon_android );
+ m.insert( "linux", icon_linux );
+ m.insert( "dribble", icon_dribble );
+ m.insert( "skype", icon_skype );
+
+ m.insert( "foursquare", icon_foursquare );
+ m.insert( "trello", icon_trello );
+ m.insert( "female", icon_female );
+ m.insert( "male", icon_male );
+ m.insert( "gittip", icon_gittip );
+ m.insert( "sun", icon_sun );
+ m.insert( "moon", icon_moon );
+ m.insert( "archive", icon_archive );
+ m.insert( "bug", icon_bug );
+ m.insert( "vk", icon_vk );
+ m.insert( "weibo", icon_weibo );
+ m.insert( "renren", icon_renren );
+
+ m.insert( "circle_close", icon_circle_close );
+
+ return true;
+}
+
+void QtAwesome::addNamedCodepoint( const QString& name, int codePoint)
+{
+ namedCodepoints_.insert( name, codePoint);
+}
+
+
+/// Sets a default option. These options are passed on to the icon painters
+void QtAwesome::setDefaultOption(const QString& name, const QVariant& value)
+{
+ defaultOptions_.insert( name, value );
+}
+
+
+/// Returns the default option for the given name
+QVariant QtAwesome::defaultOption(const QString& name)
+{
+ return defaultOptions_.value( name );
+}
+
+
+// internal helper method to merge to option amps
+static QVariantMap mergeOptions( const QVariantMap& defaults, const QVariantMap& override )
+{
+ QVariantMap result= defaults;
+ if( !override.isEmpty() ) {
+ QMapIterator<QString,QVariant> itr(override);
+ while( itr.hasNext() ) {
+ itr.next();
+ result.insert( itr.key(), itr.value() );
+ }
+ }
+ return result;
+}
+
+
+/// Creates an icon with the given code-point
+/// <code>
+/// awesome->icon( icon_group )
+/// </code>
+QIcon QtAwesome::icon(int character, const QVariantMap &options)
+{
+ // create a merged QVariantMap to have default options and icon-specific options
+ QVariantMap optionMap = mergeOptions( defaultOptions_, options );
+ optionMap.insert("text", QString( QChar(character) ) );
+
+ return icon( fontIconPainter_, optionMap );
+}
+
+
+
+/// Creates an icon with the given name
+///
+/// You can use the icon names as defined on http://fortawesome.github.io/Font-Awesome/design.html withour the 'icon-' prefix
+/// @param name the name of the icon
+/// @param options extra option to pass to the icon renderer
+QIcon QtAwesome::icon(const QString& name, const QVariantMap& options)
+{
+ // when it's a named codepoint
+ if( namedCodepoints_.count(name) ) {
+ return icon( namedCodepoints_.value(name), options );
+ }
+
+
+ // create a merged QVariantMap to have default options and icon-specific options
+ QVariantMap optionMap = mergeOptions( defaultOptions_, options );
+
+ // this method first tries to retrieve the icon
+ QtAwesomeIconPainter* painter = painterMap_.value(name);
+ if( !painter ) {
+ return QIcon();
+ }
+
+ return icon( painter, optionMap );
+}
+
+/// Create a dynamic icon by simlpy supplying a painter object
+/// The ownership of the painter is NOT transfered.
+/// @param painter a dynamic painter that is going to paint the icon
+/// @param optionmap the options to pass to the painter
+QIcon QtAwesome::icon(QtAwesomeIconPainter* painter, const QVariantMap& optionMap )
+{
+ // Warning, when you use memoryleak detection. You should turn it of for the next call
+ // QIcon's placed in gui items are often cached and not deleted when my memory-leak detection checks for leaks.
+ // I'm not sure if it's a Qt bug or something I do wrong
+ QtAwesomeIconPainterIconEngine* engine = new QtAwesomeIconPainterIconEngine( this, painter, optionMap );
+ return QIcon( engine );
+}
+
+QIcon QtAwesome::icon(int character, const QColor& color)
+{
+ QVariantMap optionMap;
+ optionMap.insert("color", color);
+ optionMap.insert("color-disabled", color);
+ optionMap.insert("color-active", color);
+ optionMap.insert("color-selected", color);
+ return icon(character, optionMap);
+}
+
+/// Adds a named icon-painter to the QtAwesome icon map
+/// As the name applies the ownership is passed over to QtAwesome
+///
+/// @param name the name of the icon
+/// @param painter the icon painter to add for this name
+void QtAwesome::give(const QString& name, QtAwesomeIconPainter* painter)
+{
+ delete painterMap_.value( name ); // delete the old one
+ painterMap_.insert( name, painter );
+}
+
+/// Creates/Gets the icon font with a given size in pixels. This can be usefull to use a label for displaying icons
+/// Example:
+///
+/// QLabel* label = new QLabel( QChar( icon_group ) );
+/// label->setFont( awesome->font(16) )
+QFont QtAwesome::font( int size )
+{
+ QFont font( fontName_);
+ font.setPixelSize(size);
+ return font;
+}
+
+QtAwesome *awesome;
--- /dev/null
+/**
+ * QtAwesome - use font-awesome (or other font icons) in your c++ / Qt Application
+ *
+ * Copyright 2013 - Reliable Bits Software by Blommers IT. All Rights Reserved.
+ * Author Rick Blommers
+ */
+
+#ifndef QTAWESOME_H
+#define QTAWESOME_H
+
+#include <QIcon>
+#include <QIconEngine>
+#include <QPainter>
+#include <QRect>
+#include <QVariantMap>
+
+
+/// A list of all icon-names with the codepoint (unicode-value) on the right
+/// You can use the names on the page http://fortawesome.github.io/Font-Awesome/design.html ( replace every dash '-' with an underscore '_')
+enum QtFontAwesomeName {
+ icon_glass = 0xf000,
+ icon_music = 0xf001,
+ icon_search = 0xf002,
+ icon_envelope = 0xf003,
+ icon_heart = 0xf004,
+ icon_star = 0xf005,
+ icon_star_empty = 0xf006,
+ icon_user = 0xf007,
+ icon_film = 0xf008,
+ icon_th_large = 0xf009,
+ icon_th = 0xf00a,
+ icon_th_list = 0xf00b,
+ icon_ok = 0xf00c,
+ icon_remove = 0xf00d,
+ icon_zoom_in = 0xf00e,
+
+ icon_zoom_out = 0xf010,
+ icon_off = 0xf011,
+ icon_signal = 0xf012,
+ icon_cog = 0xf013,
+ icon_gear = icon_cog,
+ icon_trash = 0xf014,
+ icon_home = 0xf015,
+ icon_file_alt = 0xf016,
+ icon_time = 0xf017,
+ icon_road = 0xf018,
+ icon_download_alt = 0xf019,
+ icon_download = 0xf01a,
+ icon_upload = 0xf01b,
+ icon_inbox = 0xf01c,
+ icon_play_circle = 0xf01d,
+ icon_repeat = 0xf01e,
+
+ /* \f020 doesn't work in Safari. all shifted one down */
+ icon_refresh = 0xf021,
+ icon_list_alt = 0xf022,
+ icon_lock = 0xf023,
+ icon_flag = 0xf024,
+ icon_headphones = 0xf025,
+ icon_volume_off = 0xf026,
+ icon_volume_down = 0xf027,
+ icon_volume_up = 0xf028,
+ icon_qrcode = 0xf029,
+ icon_barcode = 0xf02a,
+ icon_tag = 0xf02b,
+ icon_tags = 0xf02c,
+ icon_book = 0xf02d,
+ icon_bookmark = 0xf02e,
+ icon_print = 0xf02f,
+
+ icon_camera = 0xf030,
+ icon_font = 0xf031,
+ icon_bold = 0xf032,
+ icon_italic = 0xf033,
+ icon_text_height = 0xf034,
+ icon_text_width = 0xf035,
+ icon_align_left = 0xf036,
+ icon_align_center = 0xf037,
+ icon_align_right = 0xf038,
+ icon_align_justify = 0xf039,
+ icon_list = 0xf03a,
+ icon_indent_left = 0xf03b,
+ icon_indent_right = 0xf03c,
+ icon_facetime_video = 0xf03d,
+ icon_picture = 0xf03e,
+
+ icon_pencil = 0xf040,
+ icon_map_marker = 0xf041,
+ icon_adjust = 0xf042,
+ icon_tint = 0xf043,
+ icon_edit = 0xf044,
+ icon_share = 0xf045,
+ icon_check = 0xf046,
+ icon_move = 0xf047,
+ icon_step_backward = 0xf048,
+ icon_fast_backward = 0xf049,
+ icon_backward = 0xf04a,
+ icon_play = 0xf04b,
+ icon_pause = 0xf04c,
+ icon_stop = 0xf04d,
+ icon_forward = 0xf04e,
+
+ icon_fast_forward = 0xf050,
+ icon_step_forward = 0xf051,
+ icon_eject = 0xf052,
+ icon_chevron_left = 0xf053,
+ icon_chevron_right = 0xf054,
+ icon_plus_sign = 0xf055,
+ icon_minus_sign = 0xf056,
+ icon_remove_sign = 0xf057,
+ icon_ok_sign = 0xf058,
+ icon_question_sign = 0xf059,
+ icon_info_sign = 0xf05a,
+ icon_screenshot = 0xf05b,
+ icon_remove_circle = 0xf05c,
+ icon_ok_circle = 0xf05d,
+ icon_ban_circle = 0xf05e,
+
+ icon_arrow_left = 0xf060,
+ icon_arrow_right = 0xf061,
+ icon_arrow_up = 0xf062,
+ icon_arrow_down = 0xf063,
+ icon_share_alt = 0xf064,
+ icon_resize_full = 0xf065,
+ icon_resize_small = 0xf066,
+ icon_plus = 0xf067,
+ icon_minus = 0xf068,
+ icon_asterisk = 0xf069,
+ icon_exclamation_sign = 0xf06a,
+ icon_gift = 0xf06b,
+ icon_leaf = 0xf06c,
+ icon_fire = 0xf06d,
+ icon_eye_open = 0xf06e,
+
+ icon_eye_close = 0xf070,
+ icon_warning_sign = 0xf071,
+ icon_plane = 0xf072,
+ icon_calendar = 0xf073,
+ icon_random = 0xf074,
+ icon_comment = 0xf075,
+ icon_magnet = 0xf076,
+ icon_chevron_up = 0xf077,
+ icon_chevron_down = 0xf078,
+ icon_retweet = 0xf079,
+ icon_shopping_cart = 0xf07a,
+ icon_folder_close = 0xf07b,
+ icon_folder_open = 0xf07c,
+ icon_resize_vertical = 0xf07d,
+ icon_resize_horizontal = 0xf07e,
+
+ icon_bar_chart = 0xf080,
+ icon_twitter_sign = 0xf081,
+ icon_facebook_sign = 0xf082,
+ icon_camera_retro = 0xf083,
+ icon_key = 0xf084,
+ icon_cogs = 0xf085,
+ icon_gears = icon_cogs,
+ icon_comments = 0xf086,
+ icon_thumbs_up_alt = 0xf087,
+ icon_thumbs_down_alt = 0xf088,
+ icon_star_half = 0xf089,
+ icon_heart_empty = 0xf08a,
+ icon_signout = 0xf08b,
+ icon_linkedin_sign = 0xf08c,
+ icon_pushpin = 0xf08d,
+ icon_external_link = 0xf08e,
+
+ icon_signin = 0xf090,
+ icon_trophy = 0xf091,
+ icon_github_sign = 0xf092,
+ icon_upload_alt = 0xf093,
+ icon_lemon = 0xf094,
+ icon_phone = 0xf095,
+ icon_check_empty = 0xf096,
+ icon_bookmark_empty = 0xf097,
+ icon_phone_sign = 0xf098,
+ icon_twitter = 0xf099,
+ icon_facebook = 0xf09a,
+ icon_github = 0xf09b,
+ icon_unlock = 0xf09c,
+ icon_credit_card = 0xf09d,
+ icon_rss = 0xf09e,
+
+ icon_hdd = 0xf0a0,
+ icon_bullhorn = 0xf0a1,
+ icon_bell = 0xf0a2,
+ icon_certificate = 0xf0a3,
+ icon_hand_right = 0xf0a4,
+ icon_hand_left = 0xf0a5,
+ icon_hand_up = 0xf0a6,
+ icon_hand_down = 0xf0a7,
+ icon_circle_arrow_left = 0xf0a8,
+ icon_circle_arrow_right = 0xf0a9,
+ icon_circle_arrow_up = 0xf0aa,
+ icon_circle_arrow_down = 0xf0ab,
+ icon_globe = 0xf0ac,
+ icon_wrench = 0xf0ad,
+ icon_tasks = 0xf0ae,
+
+ icon_filter = 0xf0b0,
+ icon_briefcase = 0xf0b1,
+ icon_fullscreen = 0xf0b2,
+
+ icon_group = 0xf0c0,
+ icon_link = 0xf0c1,
+ icon_cloud = 0xf0c2,
+ icon_beaker = 0xf0c3,
+ icon_cut = 0xf0c4,
+ icon_copy = 0xf0c5,
+ icon_paper_clip = 0xf0c6,
+ icon_save = 0xf0c7,
+ icon_sign_blank = 0xf0c8,
+ icon_reorder = 0xf0c9,
+ icon_list_ul = 0xf0ca,
+ icon_list_ol = 0xf0cb,
+ icon_strikethrough = 0xf0cc,
+ icon_underline = 0xf0cd,
+ icon_table = 0xf0ce,
+
+ icon_magic = 0xf0d0,
+ icon_truck = 0xf0d1,
+ icon_pinterest = 0xf0d2,
+ icon_pinterest_sign = 0xf0d3,
+ icon_google_plus_sign = 0xf0d4,
+ icon_google_plus = 0xf0d5,
+ icon_money = 0xf0d6,
+ icon_caret_down = 0xf107,
+ icon_caret_up = 0xf106,
+ icon_caret_left = 0xf104,
+ icon_caret_right = 0xf105,
+ icon_columns = 0xf0db,
+ icon_sort = 0xf0dc,
+ icon_sort_down = 0xf0dd,
+ icon_sort_up = 0xf0de,
+
+ icon_envelope_alt = 0xf0e0,
+ icon_linkedin = 0xf0e1,
+ icon_undo = 0xf0e2,
+ icon_legal = 0xf0e3,
+ icon_dashboard = 0xf0e4,
+ icon_comment_alt = 0xf0e5,
+ icon_comments_alt = 0xf0e6,
+ icon_bolt = 0xf0e7,
+ icon_sitemap = 0xf0e8,
+ icon_umbrella = 0xf0e9,
+ icon_paste = 0xf0ea,
+ icon_lightbulb = 0xf0eb,
+ icon_exchange = 0xf0ec,
+ icon_cloud_download = 0xf0ed,
+ icon_cloud_upload = 0xf0ee,
+
+ icon_user_md = 0xf0f0,
+ icon_stethoscope = 0xf0f1,
+ icon_suitcase = 0xf0f2,
+ icon_bell_alt = 0xf0f3,
+ icon_coffee = 0xf0f4,
+ icon_food = 0xf0f5,
+ icon_file_text_alt = 0xf0f6,
+ icon_building = 0xf0f7,
+ icon_hospital = 0xf0f8,
+ icon_ambulance = 0xf0f9,
+ icon_medkit = 0xf0fa,
+ icon_fighter_jet = 0xf0fb,
+ icon_beer = 0xf0fc,
+ icon_h_sign = 0xf0fd,
+ icon_plus_sign_alt = 0xf0fe,
+
+ icon_double_angle_left = 0xf100,
+ icon_double_angle_right = 0xf101,
+ icon_double_angle_up = 0xf102,
+ icon_double_angle_down = 0xf103,
+ icon_angle_left = 0xf104,
+ icon_angle_right = 0xf105,
+ icon_angle_up = 0xf106,
+ icon_angle_down = 0xf107,
+ icon_desktop = 0xf108,
+ icon_laptop = 0xf109,
+ icon_tablet = 0xf10a,
+ icon_mobile_phone = 0xf10b,
+ icon_circle_blank = 0xf10c,
+ icon_quote_left = 0xf10d,
+ icon_quote_right = 0xf10e,
+
+ icon_spinner = 0xf110,
+ icon_circle = 0xf111,
+ icon_mail_reply = 0xf112,
+ icon_reply = icon_mail_reply,
+
+ icon_github_alt = 0xf113,
+ icon_folder_close_alt = 0xf114,
+ icon_folder_open_alt = 0xf115,
+
+ icon_expand_alt = 0xf116,
+ icon_collapse_alt = 0xf117,
+ icon_smile = 0xf118,
+ icon_frown = 0xf119,
+ icon_meh = 0xf11a,
+ icon_gamepad = 0xf11b,
+ icon_keyboard = 0xf11c,
+ icon_flag_alt = 0xf11d,
+ icon_flag_checkered = 0xf11e,
+
+ icon_terminal = 0xf120,
+ icon_code = 0xf121,
+ icon_reply_all = 0xf122,
+ icon_mail_reply_all = icon_reply_all,
+ icon_star_half_full = 0xf123,
+ icon_star_half_empty = icon_star_half_full,
+ icon_location_arrow = 0xf124,
+ icon_crop = 0xf125,
+ icon_code_fork = 0xf126,
+ icon_unlink = 0xf127,
+ icon_question = 0xf128,
+ icon_info = 0xf129,
+ icon_exclamation = 0xf12a,
+ icon_superscript = 0xf12b,
+ icon_subscript = 0xf12c,
+ icon_eraser = 0xf12d,
+ icon_puzzle_piece = 0xf12e,
+
+ icon_microphone = 0xf130,
+ icon_microphone_off = 0xf131,
+ icon_shield = 0xf132,
+ icon_calendar_empty = 0xf133,
+ icon_fire_extinguisher = 0xf134,
+ icon_rocket = 0xf135,
+ icon_maxcdn = 0xf136,
+ icon_chevron_sign_left = 0xf137,
+ icon_chevron_sign_right = 0xf138,
+ icon_chevron_sign_up = 0xf139,
+ icon_chevron_sign_down = 0xf13a,
+ icon_html5 = 0xf13b,
+ icon_css3 = 0xf13c,
+ icon_anchor = 0xf13d,
+ icon_unlock_alt = 0xf13e,
+
+ icon_bullseye = 0xf140,
+ icon_ellipsis_horizontal = 0xf141,
+ icon_ellipsis_vertical = 0xf142,
+ icon_rss_sign = 0xf143,
+ icon_play_sign = 0xf144,
+ icon_ticket = 0xf145,
+ icon_minus_sign_alt = 0xf146,
+ icon_check_minus = 0xf147,
+ icon_level_up = 0xf148,
+ icon_level_down = 0xf149,
+ icon_check_sign = 0xf14a,
+ icon_edit_sign = 0xf14b,
+ icon_external_link_sign = 0xf14c,
+ icon_share_sign = 0xf14d,
+
+ // v3.2.0
+ icon_compass = 0xf14e,
+
+ icon_collapse = 0xf150,
+ icon_collapse_top = 0xf151,
+ icon_expand = 0xf152,
+ icon_euro = 0xf153,
+ icon_eur = 0xf153,
+ icon_gbp = 0xf154,
+ icon_dollar = 0xf155,
+ icon_usd = icon_dollar,
+ icon_rupee = 0xf156,
+ icon_inr = icon_rupee,
+ icon_yen = 0xf157,
+ icon_jpy = icon_yen,
+ icon_renminbi = 0xf158,
+ icon_cny = icon_renminbi,
+ icon_won = 0xf159,
+ icon_krw = icon_won,
+ icon_bitcoin = 0xf15a,
+ icon_btc = icon_bitcoin,
+ icon_file = 0xf15b,
+ icon_file_text = 0xf15c,
+ icon_sort_by_alphabet = 0xf15d,
+ icon_sort_by_alphabet_alt = 0xf15e,
+
+ icon_sort_by_attributes = 0xf160,
+ icon_sort_by_attributes_alt = 0xf161,
+ icon_sort_by_order = 0xf162,
+ icon_sort_by_order_alt = 0xf163,
+ icon_thumbs_up = 0xf164,
+ icon_thumbs_down = 0xf165,
+ icon_youtube_sign = 0xf166,
+ icon_youtube = 0xf167,
+ icon_xing = 0xf168,
+ icon_xing_sign = 0xf169,
+ icon_youtube_play = 0xf16a,
+ icon_dropbox = 0xf16b,
+ icon_stackexchange = 0xf16c,
+ icon_instagram = 0xf16d,
+ icon_flickr = 0xf16e,
+
+ icon_adn = 0xf170,
+ icon_bitbucket = 0xf171,
+ icon_bitbucket_sign = 0xf172,
+ icon_tumblr = 0xf173,
+ icon_tumblr_sign = 0xf174,
+ icon_long_arrow_down = 0xf175,
+ icon_long_arrow_up = 0xf176,
+ icon_long_arrow_left = 0xf177,
+ icon_long_arrow_right = 0xf178,
+ icon_apple = 0xf179,
+ icon_windows = 0xf17a,
+ icon_android = 0xf17b,
+ icon_linux = 0xf17c,
+ icon_dribble = 0xf17d,
+ icon_skype = 0xf17e,
+
+ icon_foursquare = 0xf180,
+ icon_trello = 0xf181,
+ icon_female = 0xf182,
+ icon_male = 0xf183,
+ icon_gittip = 0xf184,
+ icon_sun = 0xf185,
+ icon_moon = 0xf186,
+ icon_archive = 0xf187,
+ icon_bug = 0xf188,
+ icon_vk = 0xf189,
+ icon_weibo = 0xf18a,
+ icon_renren = 0xf18b,
+
+ icon_circle_close = 0xf05c
+};
+
+
+//---------------------------------------------------------------------------------------
+
+class QtAwesomeIconPainter;
+
+/// The main class for managing icons
+/// This class requires a 2-phase construction. You must first create the class and then initialize it via an init* method
+class QtAwesome : public QObject
+{
+Q_OBJECT
+
+public:
+
+ QtAwesome(QObject *parent = 0);
+ virtual ~QtAwesome();
+
+ void init( const QString& fontname );
+ bool initFontAwesome();
+
+ void addNamedCodepoint( const QString& name, int codePoint );
+ QHash<QString,int> namedCodePoints() { return namedCodepoints_; }
+
+ void setDefaultOption( const QString& name, const QVariant& value );
+ QVariant defaultOption( const QString& name );
+
+ QIcon icon( int character, const QVariantMap& options = QVariantMap() );
+ QIcon icon( const QString& name, const QVariantMap& options = QVariantMap() );
+ QIcon icon(QtAwesomeIconPainter* painter, const QVariantMap& optionMap = QVariantMap() );
+ QIcon icon(int character, const QColor& color);
+
+ void give( const QString& name, QtAwesomeIconPainter* painter );
+
+ QFont font( int size );
+
+ /// Returns the font-name that is used as icon-map
+ QString fontName() { return fontName_ ; }
+
+private:
+ QString fontName_; ///< The font name used for this map
+ QHash<QString,int> namedCodepoints_; ///< A map with names mapped to code-points
+
+ QHash<QString, QtAwesomeIconPainter*> painterMap_; ///< A map of custom painters
+ QVariantMap defaultOptions_; ///< The default icon options
+ QtAwesomeIconPainter* fontIconPainter_; ///< A special painter fo painting codepoints
+};
+
+
+//---------------------------------------------------------------------------------------
+
+
+/// The QtAwesomeIconPainter is a specialized painter for painting icons
+/// your can implement an iconpainter to create custom font-icon code
+class QtAwesomeIconPainter
+{
+public:
+ virtual ~QtAwesomeIconPainter() {}
+ virtual void paint( QtAwesome* awesome, QPainter* painter, const QRect& rect, QIcon::Mode mode, QIcon::State state, const QVariantMap& options ) = 0;
+};
+
+extern QtAwesome *awesome;
+
+#endif // QTAWESOME_H
--- /dev/null
+<RCC>
+ <qresource prefix="/">
+ <file>fonts/fontawesome.ttf</file>
+ </qresource>
+</RCC>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AboutDialog</class>
+ <widget class="QDialog" name="AboutDialog">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>296</width>
+ <height>137</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>About</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>6</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>6</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="mVersionText">
+ <property name="font">
+ <font>
+ <family>Times New Roman</family>
+ <pointsize>18</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true">Current Version</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>6</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>7</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCheckUpdateBtn">
+ <property name="text">
+ <string>Check For Updates</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOKBtn">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>6</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>6</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="9"/>
+ <resources/>
+ <connections/>
+ <designerdata>
+ <property name="gridDeltaX">
+ <number>10</number>
+ </property>
+ <property name="gridDeltaY">
+ <number>10</number>
+ </property>
+ <property name="gridSnapX">
+ <bool>true</bool>
+ </property>
+ <property name="gridSnapY">
+ <bool>true</bool>
+ </property>
+ <property name="gridVisible">
+ <bool>false</bool>
+ </property>
+ </designerdata>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AccountSettingsDialog</class>
+ <widget class="QDialog" name="AccountSettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>483</width>
+ <height>123</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Server Address</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="mServerAddr"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Email</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="mUsername"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOkBtn">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ <zorder>mOkBtn</zorder>
+ <zorder>mServerAddr</zorder>
+ <zorder>mUsername</zorder>
+ <zorder>label</zorder>
+ <zorder>label_2</zorder>
+ <zorder></zorder>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>mCancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>AccountSettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>472</x>
+ <y>108</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>249</x>
+ <y>122</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AccountView</class>
+ <widget class="QWidget" name="AccountView">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>66</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>15</number>
+ </property>
+ <property name="topMargin">
+ <number>12</number>
+ </property>
+ <property name="rightMargin">
+ <number>15</number>
+ </property>
+ <property name="bottomMargin">
+ <number>12</number>
+ </property>
+ <item>
+ <widget class="QToolButton" name="mAccountBtn">
+ <property name="text">
+ <string>Account</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::NoArrow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>10</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mEmail">
+ <property name="text">
+ <string>email</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mServerAddr">
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="text">
+ <string>server</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>248</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="mRefreshLabel">
+ <property name="text">
+ <string notr="true">RefreshIcon</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CloneTasksDialog</class>
+ <widget class="QDialog" name="CloneTasksDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>242</width>
+ <height>47</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="mClearBtn">
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>CloneTasksDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>71</x>
+ <y>50</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>22</x>
+ <y>45</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CloudView</class>
+ <widget class="QWidget" name="CloudView">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>511</width>
+ <height>579</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="mHeader" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_9">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mLogo">
+ <property name="text">
+ <string>logo</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mBrand">
+ <property name="text">
+ <string>brand</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_10">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_10">
+ <item>
+ <widget class="QPushButton" name="mMinimizeBtn">
+ <property name="text">
+ <string>minimize</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCloseBtn">
+ <property name="text">
+ <string>close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="mDropArea" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QFrame" name="mDropInner">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_7">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_8">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mSelectFolderBtn">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Select</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mDropFolderText">
+ <property name="text">
+ <string>or Drop Folder to Sync</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QFrame" name="mFooter">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>10</number>
+ </property>
+ <property name="rightMargin">
+ <number>10</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QProgressBar" name="mStorageUsage">
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="mServerStatusBtn">
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="leftMargin">
+ <number>20</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mDownloadRate">
+ <property name="text">
+ <string>download rate</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mDownloadRateArrow">
+ <property name="text">
+ <string>downarrow</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="mUploadRate">
+ <property name="text">
+ <string>upload rate</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mUploadRateArrow">
+ <property name="text">
+ <string>uparrow</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CreateRepoDialog</class>
+ <widget class="QDialog" name="CreateRepoDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>407</width>
+ <height>247</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QFrame" name="mFrame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLineEdit" name="mDirectory"/>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mChooseDirBtn">
+ <property name="text">
+ <string>Choose</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="mName">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="mEncrypteCheckBox">
+ <property name="text">
+ <string>encrypted</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="mPasswordLabel">
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="mPassword">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="mPasswordAgainLabel">
+ <property name="text">
+ <string>Password Again:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="mPasswordAgain">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mStatusText">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>status text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOkBtn">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>mOkBtn</tabstop>
+ <tabstop>mDirectory</tabstop>
+ <tabstop>mChooseDirBtn</tabstop>
+ <tabstop>mName</tabstop>
+ <tabstop>mEncrypteCheckBox</tabstop>
+ <tabstop>mPassword</tabstop>
+ <tabstop>mPasswordAgain</tabstop>
+ <tabstop>mCancelBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>mCancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>CreateRepoDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>396</x>
+ <y>439</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>339</x>
+ <y>4</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>mEncrypteCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>mPassword</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>162</x>
+ <y>297</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>165</x>
+ <y>329</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>mEncrypteCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>mPasswordAgain</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>200</x>
+ <y>296</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>239</x>
+ <y>358</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DownloadRepoDialog</class>
+ <widget class="QDialog" name="DownloadRepoDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>551</width>
+ <height>366</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Download Library</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QFrame#mFrame {
+
+padding-top: 7px;
+
+}
+
+QLineEdit#mDirectory {
+
+min-width: 300px;
+
+}
+</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QFrame" name="mFrame">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="mRepoIcon">
+ <property name="text">
+ <string notr="true">repoIcon</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mRepoName">
+ <property name="text">
+ <string notr="true">repoName</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="mOperationText">
+ <property name="font">
+ <font>
+ <pointsize>11</pointsize>
+ </font>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="text">
+ <string notr="true">Sync to folder:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLineEdit" name="mDirectory">
+ <property name="focusPolicy">
+ <enum>Qt::StrongFocus</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mChooseDirBtn">
+ <property name="text">
+ <string>choose...</string>
+ </property>
+ <property name="default">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="topMargin">
+ <number>5</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mPasswordLabel">
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="text">
+ <string>Password for this library:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="mPassword">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mMergeHint">
+ <property name="font">
+ <font>
+ <strikeout>false</strikeout>
+ </font>
+ </property>
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QFrame" name="mSwitchToSyncFrame">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>5</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mSwitchModeHint">
+ <property name="text">
+ <string notr="true">or merge with an existing folder </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>235</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>18</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOkBtn">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ <property name="default">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>mChooseDirBtn</tabstop>
+ <tabstop>mPassword</tabstop>
+ <tabstop>mOkBtn</tabstop>
+ <tabstop>mCancelBtn</tabstop>
+ <tabstop>mDirectory</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>mCancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>DownloadRepoDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>489</x>
+ <y>283</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>339</x>
+ <y>4</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InitSeafileDialog</class>
+ <widget class="QDialog" name="InitSeafileDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>550</width>
+ <height>350</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <property name="styleSheet">
+ <string notr="true">background: white;</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mTitle">
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string>Choose a folder</string>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>348</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="mLogo">
+ <property name="text">
+ <string>logo</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>125</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>20</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mCentralText">
+ <property name="text">
+ <string>Please choose a folder. We will create a %1 subfolder in it. When you download a library, it will be saved there by default.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLineEdit" name="mDirectory">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>250</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mChooseDirBtn">
+ <property name="text">
+ <string>Choose...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>125</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="leftMargin">
+ <number>10</number>
+ </property>
+ <property name="topMargin">
+ <number>10</number>
+ </property>
+ <property name="rightMargin">
+ <number>10</number>
+ </property>
+ <property name="bottomMargin">
+ <number>10</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOkBtn">
+ <property name="text">
+ <string>Next</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ <zorder>line</zorder>
+ <zorder>line_2</zorder>
+ <zorder>widget</zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InitVirtualDriveDialog</class>
+ <widget class="QDialog" name="InitVirtualDriveDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>566</width>
+ <height>350</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLineEdit {
+min-width: 260px;
+}</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <property name="styleSheet">
+ <string notr="true">background: white;</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="mTitle">
+ <property name="font">
+ <font>
+ <family>Sans Serif</family>
+ <pointsize>11</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string>Download Default Library</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>376</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="mLogo">
+ <property name="text">
+ <string>logo</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>85</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QWidget" name="mWrapper" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="mStatusIcon">
+ <property name="text">
+ <string notr="true">TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mStatusText">
+ <property name="text">
+ <string>%1 organizes files by libraries.
+Do you like to download your default library?</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>548</width>
+ <height>17</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>85</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mYesBtn">
+ <property name="text">
+ <string>Yes</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mNoBtn">
+ <property name="text">
+ <string>Skip</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mRunInBackgroundBtn">
+ <property name="text">
+ <string>Run in Background</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOpenBtn">
+ <property name="text">
+ <string>Open</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mFinishBtn">
+ <property name="text">
+ <string>Finish</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>mYesBtn</tabstop>
+ <tabstop>mNoBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>mNoBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>InitVirtualDriveDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>299</x>
+ <y>180</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>339</x>
+ <y>4</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LoginDialog</class>
+ <widget class="QDialog" name="LoginDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>550</width>
+ <height>349</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">QLineEdit {
+min-width: 260px;
+}</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <property name="styleSheet">
+ <string notr="true">background: white;</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="mTitle">
+ <property name="font">
+ <font>
+ <family>Sans Serif</family>
+ <pointsize>11</pointsize>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <property name="text">
+ <string>Add an account</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>376</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="mLogo">
+ <property name="text">
+ <string>logo</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>85</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="topMargin">
+ <number>20</number>
+ </property>
+ <property name="bottomMargin">
+ <number>20</number>
+ </property>
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="serverUrl">
+ <property name="text">
+ <string>Server:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="mServerAddr">
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <layout class="QVBoxLayout" name="serverNoteLayout">
+ <item>
+ <widget class="QLabel" name="hint">
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="text">
+ <string><html><head/><body><p>For example: https://seacloud.cc</p></body></html></string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::AutoText</enum>
+ </property>
+ <property name="openExternalLinks">
+ <bool>false</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <height>-4</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="hint_2">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>or http://192.168.1.24:8000</string>
+ </property>
+ <property name="openExternalLinks">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <height>4</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Email / Username:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="mUsername"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="mPassword">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <layout class="QVBoxLayout" name="automaticLoginLayout">
+ <item>
+ <spacer name="verticalSpacer4">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <height>-4</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mAutomaticLogin">
+ <property name="text">
+ <string>Automatic Login</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer5">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <height>4</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Computer Name:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="mComputerName"/>
+ </item>
+ <item row="6" column="1">
+ <widget class="QLabel" name="hint_3">
+ <property name="text">
+ <string>e.g. Jim's laptop</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QLabel" name="mStatusText">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>status text</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>85</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <property name="bottomMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mShibLoginLink">
+ <property name="text">
+ <string>Single Sign On</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mSubmitBtn">
+ <property name="text">
+ <string>Login</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>mServerAddr</tabstop>
+ <tabstop>mUsername</tabstop>
+ <tabstop>mPassword</tabstop>
+ <tabstop>mComputerName</tabstop>
+ <tabstop>mSubmitBtn</tabstop>
+ <tabstop>mCancelBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>mCancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>LoginDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>299</x>
+ <y>180</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>339</x>
+ <y>4</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PrivateShareDialog</class>
+ <widget class="QDialog" name="PrivateShareDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>455</width>
+ <height>155</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QFrame" name="mFrame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Share To:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QPushButton" name="mOkBtn">
+ <property name="text">
+ <string>Share</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Permission:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="mPermission">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <item>
+ <property name="text">
+ <string>Read-Write</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Read-Only</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QStackedWidget" name="mInputStack">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="page"/>
+ <widget class="QWidget" name="page_2"/>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <property name="leftMargin">
+ <number>8</number>
+ </property>
+ <property name="rightMargin">
+ <number>8</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mStatusText">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RepoDetailDialog</class>
+ <widget class="QDialog" name="RepoDetailDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>261</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QFrame" name="mFrame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>12</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="mRepoIcon">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>RepoIcon</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="verticalSpacing">
+ <number>3</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Name:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="mRepoName">
+ <property name="text">
+ <string>RepoName</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Owner:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="mOwnerLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Last Modified:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="mTimeLabel">
+ <property name="text">
+ <string>mtime</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Size:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLabel" name="mSizeLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="lpathLabel">
+ <property name="text">
+ <string>Local Path:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QLabel" name="mLpathLabel">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Status:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="1">
+ <widget class="QLabel" name="mStatus">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="text">
+ <string>RepoStatus</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="0">
+ <widget class="QLabel" name="mSyncIntervalLabel">
+ <property name="text">
+ <string>Sync Interval:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="1">
+ <widget class="QLabel" name="mSyncInterval">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="10" column="0">
+ <spacer name="verticalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>RepoDetailDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>282</x>
+ <y>208</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>188</x>
+ <y>210</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerRepoItem</class>
+ <widget class="QWidget" name="ServerRepoItem">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>247</width>
+ <height>45</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="mRepoIcon">
+ <property name="text">
+ <string>repoicon</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mRepoName">
+ <property name="text">
+ <string>reponame</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mDownloadButton">
+ <property name="text">
+ <string>download</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerReposView</class>
+ <widget class="QWidget" name="ServerReposView">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QScrollArea" name="mScrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>245</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="mRefreshButton">
+ <property name="text">
+ <string>Refresh</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mAddRepoButton">
+ <property name="text">
+ <string>Add a repo</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ServerStatusDialog</class>
+ <widget class="QDialog" name="ServerStatusDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>274</width>
+ <height>245</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QListWidget" name="mList"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>ServerStatusDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>299</x>
+ <y>268</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>247</x>
+ <y>276</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SetRepoPasswordDialog</class>
+ <widget class="QDialog" name="SetRepoPasswordDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>432</width>
+ <height>139</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>90</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="mHintText">
+ <property name="text">
+ <string notr="true">Provide password for the library</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="mPassword">
+ <property name="inputMethodHints">
+ <set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText</set>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mErrorText">
+ <property name="text">
+ <string notr="true">error message</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOkBtn">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>mCancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SetRepoPasswordDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>389</x>
+ <y>112</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>184</x>
+ <y>114</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>724</width>
+ <height>579</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QTabWidget" name="mTabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="mBasicTab">
+ <attribute name="title">
+ <string>Basic</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QCheckBox" name="mHideMainWinCheckBox">
+ <property name="text">
+ <string>Hide main window when started</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mNotifyCheckBox">
+ <property name="text">
+ <string>Notify when libraries are synchronized</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mSyncExtraTempFileCheckBox">
+ <property name="text">
+ <string>Enable sync temporary files of MSOffice/Libreoffice</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mAutoStartCheckBox">
+ <property name="text">
+ <string>Auto start %1 after login</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mHideDockIconCheckBox">
+ <property name="text">
+ <string>Hide %1 Icon from the dock</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mFinderSyncCheckBox">
+ <property name="text">
+ <string>Enable FinderSync Extension</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mShellExtCheckBox">
+ <property name="text">
+ <string>Enable Explorer Extension</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mCheckLatestVersionBox">
+ <property name="text">
+ <string>Check for updates automatically</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="labelAlignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="formAlignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Download speed limit (KB/s):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Upload speed limit (KB/s):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="mDownloadSpinBox">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="maximum">
+ <number>100000</number>
+ </property>
+ <property name="singleStep">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="mUploadSpinBox">
+ <property name="maximumSize">
+ <size>
+ <width>100</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="maximum">
+ <number>100000</number>
+ </property>
+ <property name="singleStep">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="mAdvancedTab">
+ <attribute name="title">
+ <string>Advanced</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="mAllowInvalidWorktreeCheckBox">
+ <property name="text">
+ <string>Do not automatically unsync a library</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="desc">
+ <property name="text">
+ <string>Do not automatically unsync a library when its local directory is removed or unaccessible for other reasons.</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mAllowRepoNotFoundCheckBox">
+ <property name="text">
+ <string>Do not unsync a library when not found on server</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="desc_2">
+ <property name="text">
+ <string>Do not automatically unsync a library when it's not found on server</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mDisableVerifyHttpSyncCert">
+ <property name="text">
+ <string>Do not verify server certificate in HTTPS syncing</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mEnableSyncingWithExistingFolder">
+ <property name="text">
+ <string>Enable syncing with an existing folder with a different name</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="mLanguageTab">
+ <attribute name="title">
+ <string>Language</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="languageTabLayout">
+ <item>
+ <layout class="QHBoxLayout" name="languageLayout">
+ <item>
+ <widget class="QLabel" name="mLanguageLabel">
+ <property name="text">
+ <string>Language (need restart)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="mLanguageComboBox"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_1">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="mNetworkTab">
+ <attribute name="title">
+ <string>Network</string>
+ </attribute>
+ <widget class="QWidget" name="layoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>21</x>
+ <y>12</y>
+ <width>481</width>
+ <height>451</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="labelAlignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="formAlignment">
+ <set>Qt::AlignHCenter|Qt::AlignTop</set>
+ </property>
+ <property name="horizontalSpacing">
+ <number>10</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>5</number>
+ </property>
+ <property name="rightMargin">
+ <number>4</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="mProxyMethodLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Proxy Type:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
+ <widget class="QComboBox" name="mProxyMethodComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>246</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="mProxyHostLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Host:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="mProxyHost">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>240</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="mProxyPortLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Port:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="mProxyPort">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>256</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="text" stdset="0">
+ <string>0</string>
+ </property>
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="mProxyUsernameLabel">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Username:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="mProxyUsername">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>240</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="mProxyPasswordLabel">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QLineEdit" name="mProxyPassword">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>240</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="mProxyRequirePassword">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>240</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Proxy server requires a password</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>10</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mOkBtn">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mCancelBtn">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>mCancelBtn</sender>
+ <signal>clicked()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>711</x>
+ <y>566</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>249</x>
+ <y>249</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SslConfirmDialog</class>
+ <widget class="QDialog" name="SslConfirmDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>166</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="mHint">
+ <property name="text">
+ <string notr="true">hint</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mRememberChoiceCheckBox">
+ <property name="text">
+ <string>Remember my choice</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mYesBtn">
+ <property name="text">
+ <string>Yes</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mNoBtn">
+ <property name="text">
+ <string>No</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <tabstops>
+ <tabstop>mYesBtn</tabstop>
+ <tabstop>mRememberChoiceCheckBox</tabstop>
+ <tabstop>mNoBtn</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TwoFactorDialog</class>
+ <widget class="QDialog" name="TwoFactorDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>303</width>
+ <height>134</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="mText">
+ <property name="text">
+ <string>mText</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="mLineEdit">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>21</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>20</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="mRememberDevice">
+ <property name="text">
+ <string>Remember this device</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton_2">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mSubmit">
+ <property name="text">
+ <string>OK</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton_2</sender>
+ <signal>clicked()</signal>
+ <receiver>TwoFactorDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>167</x>
+ <y>105</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>151</x>
+ <y>66</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UninstallHelperDialog</class>
+ <widget class="QDialog" name="UninstallHelperDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>595</width>
+ <height>453</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>176</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_6">
+ <item>
+ <widget class="QLabel" name="mText">
+ <property name="text">
+ <string>text</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>175</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_5">
+ <item>
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mYesBtn">
+ <property name="text">
+ <string>Yes</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="mNoBtn">
+ <property name="text">
+ <string>No</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ <zorder>line</zorder>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>WelcomeDialog</class>
+ <widget class="QDialog" name="WelcomeDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>566</width>
+ <height>543</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="styleSheet">
+ <string notr="true">background: white;</string>
+ </property>
+ <property name="text">
+ <string>Welcome to the seafile client</string>
+ </property>
+ <property name="margin">
+ <number>15</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="mHelpImage">
+ <property name="text">
+ <string>HelpImage</string>
+ </property>
+ <property name="margin">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string><html><head/><body><p>To sync files with a Seafile server:<br/></p><p>1. Add an account (with server address and your email)</p><p>2. Download a library</p><p>3. Put files into the library and they will be uploaded to server automatically<br/></p><p>You can also create a library from any local folder. See <a href="http://www.seafile.com/en/help/install_v2/"><span style=" text-decoration: underline; color:#0000ff;">seafile online help</span></a> for more information.</p></body></html></string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="margin">
+ <number>20</number>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>101</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="rightMargin">
+ <number>9</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="pushButton">
+ <property name="text">
+ <string>Next</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>pushButton</sender>
+ <signal>clicked()</signal>
+ <receiver>WelcomeDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>347</x>
+ <y>231</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>388</x>
+ <y>258</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>